8

This may have been answered before. I see many "dynamic method overload resolution" questions, but none that deal specifically with passing a dynamic argument. In the following code, in Test, the last call to M cannot be resolved (it doesn't compile). The error is: the call is ambiguous between [the first two overloads of M].

static void M(Func<int> f) { }
static void M(Func<string> f) { }
static void M(Func<dynamic> f) { }

static dynamic DynamicObject() {
    return new object();
}

static void Test() {
    M(() => 0);
    M(() => "");
    M(() => DynamicObject()); //doesn't compile
}
  1. Why, since the type isn't statically known, does it not resolve to the overload accepting dynamic?
  2. Is it even possible for an overloaded method to use dynamic?
  3. What is the best way to resolve this?
7
  • Wouldn't you be better off using a generic here? It would still be ambiguous as is (bear in mind a dynamic can be A and can be B, how does the compiler know which to call?). But if you wanted I think you could change the methods to static void M<T>(Func<DataTime, T> f) where T : A and static void M<T>(Func<DataTime, T> f) where T : B and I think that would allow the overloading? - Certainly all of the method calls in Test should be ok? Commented Aug 26, 2011 at 20:12
  • The example is contrived, but the one part that accurately reflects my dilemma is passing dynamic to an overloaded method. How is that best resolved? Commented Aug 26, 2011 at 20:14
  • As above - don't. How can you overload an object that can be anything? Commented Aug 26, 2011 at 20:21
  • @Smudge: of course you can have an overload accepting object. See Tigran's working example. Commented Aug 26, 2011 at 20:26
  • 1
    Don't do that! Use a generic instead! Commented Aug 26, 2011 at 20:26

2 Answers 2

5

The problem here is type inference. The compiler is trying to find out which overload to use based on the argument, but it's also trying to find out what the type of the argument is based on the chosen overload. In the case of M(() => DynamicObject()), the process goes something like this:

  1. The argument to the method is a lambda with zero parameters. This gives us all three overloads as possibilities.
  2. The body of the lambda returns dynamic. Because there is an implicit conversion from dynamic to any other type, we now know all three overloads are good.
  3. Try choosing the best overload. In most cases, “best” means the most derived type. Because both int and string derive from object, the overloads with int and string are considered best.
  4. We now have two “best” overloads, which means the compiler can't actually choose one of them. The compilation fails.

Now, regarding possible solutions to your problem:

  1. Make the type of the lambda explicit, either using cast or typed local variable:

    M((Func<dynamic>)(() => DynamicObject()));
    

    or

    Func<dynamic> f = () => DynamicObject();
    M(f);
    
  2. Rename the dynamic overload to something like DynamicM. This way, you don't have to deal with overload resolution.

  3. This one feels somewhat wrong to me: make sure the dynamic overload is the only one that fits, by casting to object:

    M(() => (object)DynamicObject())
    
Sign up to request clarification or add additional context in comments.

3 Comments

Ah, I hadn't thought of Func being contravariant. I think dynamic/object being in the contravariant position is the source of the problem. I'm still wondering why it didn't include the dynamic overload in the list of possible matches.
@Daniel, this is not about contravariance. The same thing would happen if Func wasn't contravariant. And the compiler did include the dynamic overload in the first pass, but it didn't include it among one of the “best” matches.
Gotcha. You're right about it picking the most specific overload. I changed the first overload to accept Func<A> and the second Func<B> (B derives from A) and it resolved to the second one. Strange, but true.
1

From the definition in MSDN:

dynamic

Type dynamic behaves like type object in most circumstances. However, operations that contain expressions of type dynamic are not resolved or type checked by the compiler. The compiler packages together information about the operation, and that information is later used to evaluate the operation at run time. As part of the process, variables of type dynamic are compiled into variables of type object. Therefore, type dynamic exists only at compile time, not at run time

So dynamic doesn't exist when you compile, cause it needs to convert it into destination *type*, and that's why is not able to resolve it. What is destination type ?

In fact if you do something like this:

static void M(Func<int> f) { }
static void M(Func<string> f) { }
static void M(Func<object> f) { } // could be also declared like dynamic here, works by the way

static object DynamicObject()
{
    return new object();
}

static void Test()
{
    M(() => 0);
    M(() => "");
    M(() => DynamicObject());
}

It perfectly works as you want, as object is present like a type already at compile time, in difference of dynamic type which have to be converted.

14 Comments

Your example shows precisely why I thought it would work, given that dynamic is just object. Is there any way for overload resolution to work with dynamic?
No:) dynamic is not an object, it have to be converted in some type at compile time, but in this case it's not possible to understand which type is have to be its destination...
OK, so back to my original question: is there any way to have an overload that accepts dynamic, or will it never resolve?
IMHO, there is no possibility, also I never seen overloading on dynamic types. Would be curiouse to see other posts.
Aren't you describing the exact functionality that generics provide? You seem to be hung up on the word dynamic but that is not the word your after?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.