(使用.NET 4.0) 好的,我有
private Dictionary<int, Action<IMyInterface, IMyInterface>> handler {get; set;}
public void Foo<T, U>(Action<T, U> myAction)
where T : IMyInterface
where U : IMyInterface
{
// | This line Fails
// V
Action<IMyInterface, IMyInterface> anotherAction = myAction;
handler.Add(someInt, anotherAction);
}
我正在尝试将委托存储在一个通用集合中,所以我可以稍后将其拉回来调用它。 我该如何正确施展它?
答案 0 :(得分:7)
Action委托的通用参数是类型逆变的;它们不是类型协变的。因此,您可以传入 less 特定类型,但不 更多特定类型。
所以这个编译:
protected void X()
{
Action<string> A = Foo;
}
void Foo(object s) { }
但这并不是:
protected void X()
{
Action<object> A = Foo;
}
void Foo(string s) { }
从T and U : IMyInterface
开始,您的代码与第一个示例类似。
intellisense非常清楚地解释了这一点:(这里是bigger version)
答案 1 :(得分:1)
Welp ......看起来像我和我的朋友找到了一些解决方法。
public void Foo<T, U>(Action<T, U> myAction)
where T : IMyInterface
where U : IMyInterface
{
Action<IMyInterface, IMyInterface> anotherAction = (x, y) => eventHandler.Invoke((TSender)x, (TObject),y);
handler.Add(someInt, anotherAction);
}
通过简单的lambda包装,我们完成了所需的工作。
答案 2 :(得分:0)
我认为没有一种类型安全的方法来做你想要完成的事情。使用更新后的问题中的示例:
private Dictionary<int, Action<IMyInterface, IMyInterface>> handler {get; set;}
public void Foo<T, U>(Action<T, U> myAction)
where T : IMyInterface
where U : IMyInterface
{
Action<IMyInterface, IMyInterface> anotherAction = (x, y) => myAction.Invoke((T)x, (U)y);
handler.Add(someInt, anotherAction);
}
假设IMyInterface和MyImplementation定义如下:
interface IMyInterface
{
void bar();
}
class MyImplementation : IMyInterface
{
void IMyInterface.bar()
{
//Snip: Do the things
}
void nope()
{
//Snip: Do other things
}
}
class MySimplerImplementation : IMyInterface
{
void IMyInterface.bar()
{
//Snip: Do things
}
}
我们可能会发现自己处于以下情况:
void test()
{
//Create an action with a method that only MyImplementation implements
Action<MyImplementation, MyImplementation> forMyImplementationOnly =
(x, y) => x.nope();
//Use Foo (defined in the example code above) to 'cast' this
//action and add it to the handler dictionary
Foo<MyImplementation, Myimplementation>(forMyImplementationOnly);
//Retrieve the action from the handler dictionary
Action<IMyInterface, IMyInterface> castedAction = handler[someInt];
//Try running the action using MySimplerImplementation
castedAction(new MySimplerImplementation(), new MySimplerImplementation());
//This code will fail because MySimplerImplementation
//can not be cast to MyImplementation. It does not even
//define the nope() method that your initial Action required
}
正是由于这个原因,Action泛型是逆变的(你可以使用较少的特定类型,但不是更具体的类型)。