Poor interoperability between static and dynamic C #

This question is somewhat illustrative of the post, I believe that the example below describes the essence of the problem.

class Program { public static IList<string> GetData(string arg) { return new string[] {"a", "b", "c"}; } static void Main(string[] args) { var arg1 = "abc"; var res1 = GetData(arg1); Console.WriteLine(res1.Count()); dynamic arg2 = "abc"; var res2 = GetData(arg2); try { Console.WriteLine(res2.Count()); } catch (RuntimeBinderException) { Console.WriteLine("Exception when accessing Count method"); } IEnumerable<string> res3 = res2; Console.WriteLine(res3.Count()); } } 

Is it not bad that the second GetData call throws an exception only because GetData received the parameter added to the dynamic? The method itself is good with this argument: it treats it as a string and returns the correct result. But the result is then converted back to dynamic, and suddenly the data cannot be processed in accordance with its basic type. If it does not explicitly return to the static type, as we see in the last lines of the example.

I did not understand why this should have been implemented in this way. This disrupts the interaction between static and dynamic types. Once the dynamics are used, it seems to infect the rest of the call chain, potentially causing problems like this.

UPDATE Some people have indicated that Count () is an extension method, and it makes sense that it is not recognized. Then I changed the call of res2.Count () to res2.Count (from the extension method to the Ilist property), but the program raised the same exception in the same place! This is strange.

UPDATE2. flq pointed out Eric Lippert's posts on this topic, and I believe that this post gives sufficient arguments in favor of why it is implemented in this way: http://blogs.msdn.com/b/ericlippert/archive/2012/10/ 22 / a-method-group-of-one.aspx

+6
source share
1 answer

The problem is that Count is an extension method.

How to find extension methods at runtime? The information about what is β€œin scope” is based on the β€œuse” operations in the specific file being compiled. However, they are not included in compiled code at runtime. Should he look at all the possible extension methods in all loaded assemblies? What about assemblies referenced by the project but not yet loaded? There are an amazing number of boundary cases that arise when trying to dynamically use extension methods.

The correct solution in this case is to call the static method in its form without extension:

Enumerable.Count(res2)

Or, since you know this IList<T> in this case, just use the Count property:

res2.Count & lt --- --- EDIT: This does not work because it is an explicitly implemented property of the interface when implemented by an array.


Once again, looking at your question, I see that the real question is not in resolving the extension method as such, but in why it cannot determine that there is a single method resolution, and therefore know the type statically. I should think about this a bit more, but I assume this is a similar question about boundary cases, especially after you start looking at multiple overloads.


Here is one unpleasant boundary case that may arise in the general case (although it does not apply directly to your case, since you exit Object).

Suppose you have a Base class in assembly A. There is also a Derived: Base class in assembly B. In the Derived class, you have the code above, and you think there is only one possible resolution for GetData. However, now suppose that a new version of assembly A is published, which has a secure GetData method with a different signature. Your derived class inherits this, and DLR dutifully allows dynamic binding to this new method. Suddenly, the return type may not be what you expected. Please note that all this can happen if you do not recompile assembly B. This means that the compiler cannot begin to assume that DLR will be allowed to the type, which, according to the predictor, is the only option, since the dynamic environment during runtimes may give a different type.

+7
source

All Articles