问题
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