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?
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With