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

时间:2012-01-11 01:51:34

标签: c# generics casting delegates xna

(使用.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 个答案:

答案 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

enter image description here

答案 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泛型是逆变的(你可以使用较少的特定类型,但不是更具体的类型)。