Overload Resolution in C# 4.0 using dynamic types
Asked Answered
C

1

6

I don't have access to the C# 4.0 preview yet. But I am curious, what does the C# 4.0 runtime do when invoking an overloaded method in the following case. Does it resolve to the generic overload ... or the specialized overload.

public class Foo<T>
{
  protected string BarImpl( T value ) { return "Bar(T) says: " + value.ToString(); }

  protected string BarImpl( int value ) { return "Bar(int) says: " + value.ToString(); }

  public string Bar( T value )
  {
    dynamic foo = this;
    return foo.BarImpl( value );
  }
}

public static void Main( string args[] )
{
  var f = new Foo<int>();

  Console.WriteLine( f.Bar( 0 ) );
}
Charlenecharleroi answered 12/6, 2009 at 15:9 Comment(0)
S
6

In general, my understanding that the result should (whenever possible) be the same as the result would be if you compiled the same code with just the dynamic expressions replaced by expressions of the type that the dynamic value has at execution time. (Statically-known types are preserved in the call site info.)

In this particular case, having just your code with .NET 4.0b1, the result is:

Bar(int) says: 0

However, having looked at this again (and checked which bit is actually dynamic) I'm slightly confused. I think it's one of those situations where I'd have to look very carefully at the spec to understand what the correct behaviour is. Unfortunately I don't know when the C# 4.0 spec will be available.

It's a tricky one to reason about, and I suspect the key part is whether at execution time the binder is able to work out that the value is of type T for the same T as the receiver, rather than type int. Because the receiver is dynamic in this case, the compiler doesn't do any overload resolution at all. Hmm. Tricky one, definitely.

Sufficient answered 12/6, 2009 at 15:20 Comment(11)
I've read the series ... there wasn't a clear case analogous to my example, so I can't be certain. The impression I get from what I've read is that Bar( int ) will get called. Which would be very nice, because it would make it possible for me to use dynamic as a way to implement C# generic type specialization ... something that up until now hasn't been very easy (or elegant) to do.Charlenecharleroi
Yup, Bar(int) is called. I've edited my answer because I'd slightly misread your question. And yes, it's handy to use dynamic to do all kinds of things like this. I like the case where you know something is a Foo<T> really, but you don't know what T is, so you can't call any generic methods...Sufficient
I hadn't thought of this sort of specialization before though... very interesting. I wonder how efficient it'll turn out to be. I've seen pretty good performance from the DLR so far.Sufficient
This behavior is different from C# 3.5 without the dynamic keyword. Calling foo.Bar(0) returns "Bar(T) says 0" in that case.Charlenecharleroi
I've recently implemented a version of generic type specialization that uses Linq.Expression to build dynamic delegates for .NET 3.5 - it works, I'm just trying to optimize the performance before I post an article online about the technique. My hope is that with C# 4.0 - dynamic will be a better and more performance way to achieve the same results.Charlenecharleroi
@LBushkin:foo.Bar(0) returns "Bar(T) says 0" because the compile-time type of "value" is T. If you change the compile-time type to int, it will return "Bar(int) says 0". That's what I meant by the bit of my answer where I talk about dynamic expressions being replaced by values of the type that the dynamic value has at execution time.Sufficient
(Having said which, I think the final bit of my answer is incorrect... I'll edit.)Sufficient
Yup, I get how the compiler resolves the overloads - I just think it's interesting that the DLR resolves the calls differently. I suspect that can introduce unexpected behavioral differences in an application - just by switching from using strong typing to dynamic typing. Not something that most people would expect - and a tricky thing to debug I imagine. However, this behavior can also be useful in certain contexts - such as for my idea to use it for generic type specialization.Charlenecharleroi
Just don't forget that it could still change before C# 4 finally ships. Unfortunately I could really do with understanding it better than I do, in order to write about it sensibly.Sufficient
The link is broken.Judgment
@John: Thanks, I've removed the paragraph as it looks like the blog posts are basically gone.Sufficient

© 2022 - 2024 — McMap. All rights reserved.