使用接口将通用委托转换为另一种类型

3
(使用.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);
    }

我想把委托存储在一个通用的集合中,以便稍后可以将其取出来调用。如何正确地进行类型转换?
3个回答

7

Action委托的通用参数是逆变类型; 它们不是协变类型。 因此,您可以传递一个比较不具体的类型,但不能传递一个更具体的类型。

因此,这个能编译通过:

protected void X()
{
    Action<string> A = Foo;
}

void Foo(object s) { }

但是这个不行:
protected void X()
{
    Action<object> A = Foo;
}

void Foo(string s) { }

由于T和U:IMyInterface,你的代码类似于第一个例子。

智能感知解释得相当清楚:(这是一个更大的版本

enter image description here


1

好吧...看起来我和我的朋友找到了一种解决方法。

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包装,我们实现了我们所需的功能。

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 泛型是逆变的(你可以使用不太具体的类型,但不能使用更具体的类型)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接