Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add dynamic to IList<T> fails

Tags:

c#

dynamic

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?

like image 590
Gerd K Avatar asked Jul 09 '18 07:07

Gerd K


1 Answers

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).

like image 134
Jon Hanna Avatar answered Oct 30 '22 05:10

Jon Hanna