0

I've been debugging this problem for hours and finally found the culprit for the problem. Let me explain the setup.

(I've got these interfaces and classes that implement them A,B)

public interface IA { public void DoSomething(int i); }
public interface IB : IA { public void SomethingElse(); }

(in some method in some class)

dynamic options = JSonConvert.DeserializeObject<dynamic>(json);
var id = int.Parse(options.someId.ToString());

IB b = new B();
b.DoSomething(id);

This code compiles as expect but at runtime I get "IB does not contain a definition for 'DoSomething'".

However, if I change to:

var id = 1;
IB b = new B();
b.DoSomething(id);

Then everything works!

Similar things have happened previously when I've used dynamic inside a method. What is going on here? Does anyone know?

Note: I can easily avoid this by moving the two lines into a different method or avoid using dynamic altogether but I'm just qurious to why :)

Fun fact: When I had 'DoSomething' and 'SomethingElse' inside one interface and one class this didnt cause any problems...

AndersLindas
  • 137
  • 1
  • 9
  • Dynamic contagion. `id` is dynamic so the compiler declines to make any assumptions about anything returned by any method it goes into. Everything is treated as dynamic, and the rules are different. Try `int id = (int)options.someId;` or something and see what happens. – 15ee8f99-57ff-4f92-890c-b56153 Oct 25 '17 at 15:05
  • 2
    Can you show as a real code? Consider preparing [mcve](https://stackoverflow.com/help/mcve). – Sinatr Oct 25 '17 at 15:07
  • @EdPlunkett I'm genuinely curious, wouldn't the compiler resolve `var id` to `int id` once it sees the right side of the statement: `int.Parse(`? – DiskJunky Oct 25 '17 at 15:08
  • 1
    @DiskJunky When there's a `dynamic` involved, overload resolution takes place at runtime. The compiler hasn't a clue what method will actually be called. It's likely to be grandpa's old familiar `int.Parse()`, but "likely" doesn't cut it. – 15ee8f99-57ff-4f92-890c-b56153 Oct 25 '17 at 15:09
  • @YvetteColomb I don't have the energy at the moment to do the research and make sure I've got everything 100% nailed down and Servy-proof. The question is a duplicate anyway. – 15ee8f99-57ff-4f92-890c-b56153 Oct 25 '17 at 15:10
  • 2
    You could have verified all of this by hovering over `var`. Never assume types when using `dynamic` because you quite literally are throwing away the typing system. – Jeroen Vannevel Oct 25 '17 at 15:11
  • I can confirm that @EdPlunkett solution works. By explisitly setting "int id = int.Parse(...)" then it works. I still don't understand what happens and why Visual Studio doesnt warn me about this. I'll try read up on overload resolution. – AndersLindas Oct 25 '17 at 15:13
  • Look like [duplicate](https://stackoverflow.com/q/41415458/1997232). – Sinatr Oct 25 '17 at 15:13
  • 1
    @AndersLindas It's calling normal `int.Parse()`; there's no overload of that. The problem is that with `dynamic`, the compiler assumes that there *could* be, so it just says "Blah, it's all dynamic, whatever" -- so then `b` is `dynamic`, which means it resolves method calls at runtime, and runtime method resolution ignores base classes or something, I'm not recalling the exact details. But that's the point of failure: Resolving methods at runtime works differently, and it's resolving `DoSomething()` at runtime because there's a `dynamic` upstream. – 15ee8f99-57ff-4f92-890c-b56153 Oct 25 '17 at 15:17
  • In a nutshell, you need to limit the contagion and write the code such that the compiler can get back to knowing with certainty what the types of things will be at runtime. – 15ee8f99-57ff-4f92-890c-b56153 Oct 25 '17 at 15:19

1 Answers1

-1

As pointed out by @EdPlunkett using "int" instead of "var" does work. If you read the comments on the first post you'll find his explanation for why this happens.

AndersLindas
  • 137
  • 1
  • 9