1

I have a long list of method overloads M(...), and I wanted to provide a general method M(object) that would invoke the correct overload based on the object's type. Just before I coded a big if-statement for invoking the correct overload, I realized C# 4 has the dynamic keyword. So I wrote this:

class X
{
    public void M(int x)
    { Console.WriteLine("M(int)"); }

    public void M(long x)
    { Console.WriteLine("M(long)"); }

    // ...20 more overloads of M() here...

    // For if you have an object of an unknown type:
    public void M(dynamic x)
    { M(x); }
}

And when I use it correctly everything is fine. However, when I provide a wrong type of value, dynamic overload resolution (obviously) recurses to M(dynamic), then tries again, resulting in an infinite recursion and eventually a StackOverflowException.

X x = new X();
x.M((int)10);               // "M(int)"
x.M((long)10);              // "M(long)"
x.M((object)10);            // "M(int)"
x.M((object)String.Empty);  // StackOverflowException

Of course, the M(dynamic) overload is technically the same as M(object), so overload resolution will pick the dynamic overload again and again and again...

How can I prevent this?

1
  • Note that dynamic was introduced into C# 4. Commented Apr 17, 2013 at 15:28

2 Answers 2

3

The simplest way of doing this so that the caller doesn't need to do anything is to separate "public method to be called" from "implementation":

public void M(dynamic x)
{
    MImpl(x);
}

private void MImpl(int x)
{
    Console.WriteLine("M(int)");
}

// etc

private void MImpl(object x)
{
    // No more specific overloads matched. Throw some appropriate exception,
    // or take a default action.
}
Sign up to request clarification or add additional context in comments.

4 Comments

You mean for each M(..) method a corresponding private MImpl(..) method, and then let the DLR do overload resolution on MImpl instead of M?
@Virtlink: No, you just have a single M method which dispatches dynamically to any number of MImpl methods.
Statically typed overloading is much faster than dynamic, and provides helpful hints to users, so in most cases I want to simply use static types. Otherwise I wouldn't have made the other overloads public, obviously.
@Virtlink: In that case you could provide M overloads which just delegate down to MImpl overloads. That would definitely work... but your requirements aren't really clear to be honest. (Especially when you bring performance in, when it isn't mentioned in your question.)
0

I realized that the M(dynamic) overload should not be provided. To get the same behavior, let instead the caller invoke the method dynamically. Like this:

X x = new X();
x.M((int)10);               // "M(int)"
x.M((long)10);              // "M(long)"
x.M((dynamic)10);           // "M(int)"
x.M((dynamic)String.Empty); // RuntimeBinderException

Comments

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.