Add dynamic to IList<T> fails

不打扰是莪最后的温柔 提交于 2021-02-07 11:54:08

问题


In the following code example the call l.Add(s) and c.Add(s) is successful, but it fails when for a generic IList<string>.

    var l = new List<string>();
    dynamic s = "s";
    l.Add(s);
    var c = (ICollection<string>)l;
    c.Add(s);
    var i = (IList<string>)l;
    i.Add("s"); // works
    i.Add(s); // fails

https://dotnetfiddle.net/Xll2If

Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: No overload for method 'Add' takes '1' arguments at CallSite.Target(Closure , CallSite , IList`1 , Object ) at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid2[T0,T1](CallSite site, T0 arg0, T1 arg1) at Program.Main() in C:\Dev\PlayGround\PlayGround\Program.cs:line 13

IList<T> derives from ICollection<T>. Can someone explain why the call for IList.Add fails?


回答1:


In looking up methods to bind a call a compiler (whether static or dynamic) may have to check on base types.

Generally with uses of dynamic we're dealing with a calls to methods on the dynamic object itself, so the dynamic compiler starts with the concrete type of the object being used via dynamic and need only go up its inheritance chain until it reaches object to look for them.

In the case where a dynamic object is passed as an argument to a method call on something statically referenced as an interface type though, the dynamic binder sadly does the same thing: if it doesn't find the method on the type in question it then looks at the BaseType of that type, which for an interface is null. So it behaves the same as it would if it had checked the inheritance correctly and failed to find the method in question and throws the appropriate exception for that case. (Note that this also means it would fail to find the Equals method defined on object).

What it should do for such cases is to check all of the interfaces implemented by the interface type in question.

This bug is fixed in .NET Core but the fix has not been ported to .NET Framework. If you want to file a bug report against netfx you might want to reference that fix in corefx.

It is sometimes possible to workaround this problem by accessing the interface type itself through the base interface where the method used is defined, or as itself being dynamic (so the appropriate method is found in whichever concreted type implements it).




回答2:


This is just a (long) comment. The following also produces the error (or a closely related one):

public interface IBase
{
  void Add(string s);
}
public interface IDerived : IBase
{
}
public class Concrete : IDerived
{
  public void Add(string s)
  {
  }
}

And then:

    IDerived i = new Concrete();
    i.Add((dynamic)"s");

My bet is this is an error in the run-time binding code emitted by the C# compiler.



来源:https://stackoverflow.com/questions/51240596/add-dynamic-to-ilistt-fails

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