Reputation: 9353
Why can’t we cast an instance of a delegate to a generic type T
?
Consider a utility method CreateDelegate
that creates an instance of T, which is a delegate, i.e. a type derived from MulticastDelegate
.
T CreateDelegate<T>() {… }
Unfortunately generics does not allow to constraint T
to a type derived from MulticastDelegate
giving the following compilation error:
Constraint cannot be special class 'System.MulticastDelegate'
Nevertheless, this utility method is checking that T
is compatible with MulticastDelegate
and creating a delegate via Reflection through Delegate::CreateDelegate
. But, if we try to cast the result of Delegate::CreateDelegate
to T
, we will get the following compilation error:
Cannot convert type 'System.Delegate' to 'T'
However, if I cast it first to object
and then to T
it will work fine:
T h = (T) ((object) Delegate.CreateDelegate(typeof(T), target, m));
Why can’t we directly cast delegate to T?
Upvotes: 8
Views: 2157
Reputation: 27962
The C# language imposes a static check whether a cast from type X to type Y is valid — i.e. whether it makes sense in that the compiler can (to certain degree) guarantee compatibility and reject errors that as clear on compile-time. An unconstrained generic type T
and System.Delegate
have nothing directly in common. However, when casted to object
the compiler knows that every type is esentially an object
, so it allows the cast. That doesn't mean a run-time type check won't fail in a particular case.
The as
operator is a little bit more permissive, as it won't cause an exception for an otherwise-invalid cast. The compiler is also less-strict in applying static checks. In your particular case this is helpful as you can omit the intermediate cast to object
and use as T
. However, one this required is that as
works on class types only, so you have to apply the where T : class
constraint.
So the method then would look like this (simplified):
public T CreateDelegate<T>(…) where T : class
{
return Delegate.CreateDelegate(typeof(T), …) as T;
}
As @usr suggested, a recommended reading is Eric Lippert's blog, e.g. this article on casts and type parameters.
Upvotes: 14