我正在尝试为共享公共(public)签名但在许多不同且不相关的类型上定义的方法创建开放实例委托(delegate)。这些方法用自定义属性标记,在运行时我查找所有用这个属性标记的方法,以便从它们的MethodInfo
中构造委托(delegate)。 s。例如,给定委托(delegate):
delegate void OpenActionDelegate(object instance, float someParam);
我想匹配的方法:
void Foo.SomeAction(float someParam);
void Bar.SomeOtherAction(float someParam);
在哪里
Foo
和 Bar
是完全不相关的类。配备MethodInfo
对于任何一种方法,我都希望最终能够像这样获得一个开放的委托(delegate):MethodInfo fm = typeof(Foo).GetMethod("SomeAction", BindingFlags.Public | BindingFlags.Instance);
MethodInfo bm = typeof(Bar).GetMethod("SomeOtherAction", BindingFlags.Public | BindingFlags.Instance);
OpenActionDelegate fd = (OpenActionDelegate)Delegate.CreateDelegate(typeof(OpenActionDelegate), fm);
OpenActionDelegate bd = (OpenActionDelegate)Delegate.CreateDelegate(typeof(OpenActionDelegate), bm);
我遇到的问题是委托(delegate)中显式实例规范的类型。由于这些方法没有保证它们将被定义的基本类型,我尝试设置
object
.但试图绑定(bind) MethodInfo
失败,大概是因为绑定(bind)委托(delegate)时参数类型不是协变的。切换委托(delegate)签名以使实例参数的类型为 Foo
或 Bar
用于绑定(bind)相应的MethodInfo
.我不相信像这样绑定(bind)开放委托(delegate)实际上是可能的,因为这样显式实例参数就不会是调用该方法的适当类型。困扰我的是可以将封闭的委托(delegate)绑定(bind)到
MethodInfo
任何声明类型,因为它不包括麻烦的实例类型。例如,我可以将封闭的委托(delegate)绑定(bind)到 null
实例,然后使用 GetField("_target").SetValue(del, instance)
在调用它们之前在委托(delegate)上。但这有点骇人听闻。现在,如果有替代解决方案,我希望这样做的原因是在直接调用
MethodInfo
时避免堆分配和值类型装箱。 s,即:someActionInfo.Invoke(instance, new object[] { someParam });
这会导致
float
的装箱。类型和 object[]
数组在堆上分配,两者都会缓慢地为其他一次性调用生成堆垃圾。
最佳答案
参数类型,包括隐含的“this”参数,显然不能是协变的并且仍然是类型安全的。暂时忘记实例方法,只考虑静态方法。如果你有
static void Foo(Mammal m) {}
那么你不能将它分配给一个接受动物的委托(delegate),因为该委托(delegate)的调用者可以传入一个水母。不过,您可以将其分配给带长颈鹿的委托(delegate),因为调用者只能传入长颈鹿,而长颈鹿是哺乳动物。
简而言之,为了类型安全,您需要逆变,而不是参数的协变。
C# 确实以多种方式支持这一点。首先,在 C# 4 中,您可以这样做:
Action<Mammal> aa = m=>m.GrowHair();
Action<Giraffe> ag = aa;
也就是说,当可变类型参数是引用类型时,通用操作类型的转换是逆变的。
其次,在 C# 2 及更高版本中,您可以这样做:
Action<Giraffe> aa = myMammal.GrowHair;
也就是说,方法组到委托(delegate)的转换在方法的参数类型中是逆变的。
但是您想要的协方差类型不是类型安全的,因此不受支持。
关于c# - 开放实例委托(delegate)上的协变实例类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6022891/