Dynamic Action<T> : Invalid Arguments when executed

大憨熊 提交于 2019-12-23 15:34:14

问题


I have a lot of places in my decently sized project where I need to switch on a type. Obviously I can't do that in .NET (in a way simple enough to satisfy me), so I have to do a decent amount of casting. This code is the result of trying to hide some of that in a proof of concept.

I have a simple inheritence modeled:

public class Base { }
public class Derived : Base { public string Name { get; set; } }

and my class:

public sealed class TypeSwitch<T> 
{
    private Dictionary<Type, dynamic> _dict;

    public TypeSwitch()
    {
        _dict = new Dictionary<Type, dynamic>();
    }

    public TypeSwitch<T> Add<K>(Action<K> action) where K : T
    {
        _dict.Add(typeof(K), action);
        return this;
    } 

    public void Execute(T item)
    {
        var type = item.GetType();
        var action = _dict[type];

        action(item);
    }
}

and I run it with:

static void Main(string[] args)
{
    var ts = new TypeSwitch<Base>();
    ts.Add<Derived>(d => { Console.WriteLine(d.Name); });

    Base b = new Derived { Name = "Jonesopolis" };
    ts.Execute(b);
}    

When I get to action(item) I get a RuntimeBinderException saying

Additional information: Delegate 'System.Action<ConsoleApp.Derived>' has some invalid arguments

This would be pretty slick and helpful if I could get it working. Can someone explain to me what I'm missing? Is it possible to get this working?


回答1:


Try another level of lambdas. In addition to working, I expect this would be considerably faster than using dynamic, even though there are two delegates being invoked.

public sealed class TypeSwitch<T>
{
    private Dictionary<Type, Action<T>> _dict; // no longer dynamic

    public TypeSwitch()
    {
        _dict = new Dictionary<Type, Action<T>>();  // no longer dynamic
    }

    public TypeSwitch<T> Add<K>(Action<K> action) where K : T
    {
        _dict.Add(typeof (K), o => action((K) o)); // outer lambda casts the value before calling the inner lambda
        return this;
    }

    public void Execute(T item)
    {
        var type = item.GetType();
        var action = _dict[type];
        action(item);
    }
}



回答2:


Your item parameter is not dynamic. Because it's statically typed as T, that type T (which happens to be Base) will be used for overload resolution. Action<Derived> cannot be invoked with a Base argument.

To use dynamic here, you need to make item dynamic too: change action(item); to action((dynamic) item);.



来源:https://stackoverflow.com/questions/32512153/dynamic-actiont-invalid-arguments-when-executed

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!