I'm trying to create an open instance delegate for a generic interface method, but I keep receiving a NotSupportedException. Here is the simplified code that won't run:
interface IFoo
{
void Bar<T>(T j);
}
class Foo : IFoo
{
public void Bar<T>(T j)
{
}
}
static void Main(string[] args)
{
var bar = typeof(IFoo).GetMethod("Bar").MakeGenericMethod(typeof(int));
var x = Delegate.CreateDelegate(typeof(Action<IFoo, int>), null, bar);
}
The last line throws NotSupportedException, "Specified method is not supported". By comparison, a non-generic open instance delegate runs fine:
interface IFoo
{
void Bar(int j);
}
class Foo : IFoo
{
public void Bar(int j)
{
}
}
static void Main(string[] args)
{
var bar = typeof(IFoo).GetMethod("Bar");
var x = Delegate.CreateDelegate(typeof(Action<IFoo, int>), null, bar);
}
And a closed generic delegate also works:
interface IFoo
{
void Bar<T>(T j);
}
class Foo : IFoo
{
public void Bar<T>(T j)
{
}
}
static void Main(string[] args)
{
var bar = typeof(IFoo).GetMethod("Bar").MakeGenericMethod(typeof(int));
var x = Delegate.CreateDelegate(typeof(Action<int>), new Foo(), bar);
}
So the recipe for closed generic delegates and open instance delegates work separately, but not when combined. It's starting to look like either a runtime bug, or intentional omission. Anyone have any insight here?
Unusually if you really need this and don't mind throwing too much infrastructure at the problem, you can use
ldvirtftn
andcalli
.It seems very strange to me as that's what I thought was what a delegate did behind the scene basically do the following...
Ldvirtftn
does a look up to figure out the function pointer to be invoked for this particular method. If you use a non-virtual generic method the performance is about the same as a delegate bound to the same function. And if it is a virtual generic method its about twice as slow, that said its still works so that's quite an improvement.I created this using reflection.emit and it seems to work just fine and it can invoke a closed virtual generic method. Unfortunately, unlike a delegate this type is bound to a specific method. However, quite a pain in the butt is that the runtime doesn't allow you to create a dynamic method that uses
ldvirtftn
,ldftn
, orcalli
opcode.If you are okay with code generation you can use expression trees or dynamicmethod to just invoke the method. It's a little slower than a direct delegate but we're talking a tiny overhead.
This is a recap of the topic and this specific issue for those that find this question (since it seems the OP has already got his answer on Microsoft Connect).
Answer
Creating an open instance generic delegate for a generic interface method is impossible (As confirmed by Microsoft here). Currently, it is possible to implement any of the following combinations of open-instance/closed static, generic/non-generic, interface/class methods (with code samples provided at the end of the answer):
Usually, the best replacement for an open instance generic delegate for a generic interface method is an open instance generic delegate for a generic class method.
Code Samples
open instance non-generic delegate for a non-generic interface method
closed static generic delegate for a generic interface method
closed static non-generic delegate for a non-generic interface method
open instance generic delegate for a generic class method
open instance non-generic delegate for a non-generic class method
closed static generic delegate for a generic class method
closed static non-generic delegate for a non-generic class method
Microsoft has answered that it's a known problem that the CLR can't do this, but it can't be solved in the current version of .NET. It's still not at all clear why this isn't possible as I explain there. Open delegates must not reuse the dispatching logic used everywhere else in the CLR for some reason, which just seems bizarre to me.