1

I like to understand how dynamic keyword works in this following code. I found a number of posts that talks about how calling Add() on IList cause RuntimeBinderException, but doesn't quite explain why the following code does not work:

    [TestFixture]
public class TestDynamicOfIList
{
    [Test]
    public void Test1()
    {
        dynamic d1 = new ClassA();
        dynamic d2 = new ClassA();

        List<dynamic> dynamicList = new List<dynamic>();

        dynamicList.Add(d1);
        dynamicList.Add(d2);

        ClassGroup group = new ClassGroup();

        foreach (dynamic dynamicClassA in dynamicList)
        {
            // using var will fail during runtime! Need to use explicit type
            var sameObject = DoNothing(dynamicClassA);
            group.ClassAList.Add(sameObject);
        }
    }

    private ClassA DoNothing(dynamic classA)
    {
        return classA;
    }

    public class ClassA
    {
    }

    public class ClassGroup
    {
        public IList<ClassA> ClassAList { get;  } = new List<ClassA>();
    }
}

}

In the above code, the ClassGroup.ClassAList property has a defined class 'ClassA' for the generic IList<>, I can't see why the compiler failed to do type checking, nor the it fails during runtime.

Here a couple of similar questions that I found on StackOverflow:

How to create a List with a dynamic object type C#

Does not contain a definition for "Add"

Why when I use var sameObject it will not work it, but using ClassA sameObject it works fine? It seems to think that the type of sameObject variable is dynamic, when the method DoNothing() clearly returns ClassA

Community
  • 1
  • 1
dsum
  • 1,433
  • 1
  • 14
  • 29
  • I believe this is a duplicate of this question: http://stackoverflow.com/q/9382130/573218 – John Koerner Jan 31 '17 at 02:12
  • Actually, after consideration, it is not an exact duplicate. The linked question does explain why sameObject is determined to be dynamic by the compiler. – John Koerner Jan 31 '17 at 02:20

2 Answers2

2

This question answers why sameObject is determined to be dynamic by the compiler.

A simpler example to demonstrate this would be:

dynamic d1 = new ClassA();
var s = DoNothing(d1);
IList<ClassA> c = new List<ClassA>();
c.Add(s);

The reason the Add to the IList doesn't work seems to come down to overload resolution. The runtime can't find an overload of Add on IList to use, so it throws an exception. You already know that if you explicitly state the type that it works, so that is a possible solution to the problem.

Interestingly, if you use ICollection<ClassA> (as suggested here), it does work, so it seems to be an issue with the IList interface:

dynamic d1 = new ClassA();
var s = DoNothing(d1);
ICollection<ClassA> c = new List<ClassA>();
c.Add(s);
Community
  • 1
  • 1
John Koerner
  • 37,428
  • 8
  • 84
  • 134
  • 1
    It also works, when Using `IList` and `Insert` instead of `Add`. `Insert` is directly declared in `IList`. So, it seems that runtime resolution of method calls cannot find methods in an interface inherited from another interface, probably because interface inheritance does not include implementation inheritance. – NineBerry Jan 31 '17 at 02:40
-1

I would really like to know why using "var sameObject" will not work

You are trying to call Add on IList and that is why it is not working. You can fix the issue 2 ways:

Fix 1

Call ToList() and then add the object.

group.ClassAList.ToList().Add(sameObject);

Fix 2

Return List from your property:

public class ClassGroup
{
    public List<ClassA> ClassAList { get;  } = new List<ClassA>();
}
CodingYoshi
  • 25,467
  • 4
  • 62
  • 64