【问题标题】:Method calling inside a foreach with dynamic list causes RuntimeBinderException "does not contain a definition for 'Add'" [duplicate]使用动态列表在 foreach 内调用方法会导致 RuntimeBinderException“不包含‘添加’的定义”[重复]
【发布时间】:2017-01-31 01:40:48
【问题描述】:

我想了解动态关键字在以下代码中的工作原理。我发现许多帖子讨论了如何在 IList 上调用 Add() 导致 RuntimeBinderException,但并没有完全解释为什么以下代码不起作用:

    [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>();
    }
}

}

在上面的代码中,ClassGroup.ClassAList 属性为泛型 IList 定义了一个类“ClassA”,我看不出为什么编译器无法进行类型检查,也看不出它在运行时会失败。

我在 StackOverflow 上发现了几个类似的问题:

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

Does not contain a definition for "Add"

为什么我用var sameObject的时候不行,但是用ClassA sameObject就可以了?好像认为sameObject变量的类型是动态的,当方法DoNothing() 明确返回ClassA

【问题讨论】:

  • 我相信这是这个问题的重复:stackoverflow.com/q/9382130/573218
  • 其实经过考虑,并不是一模一样的。链接的问题确实解释了为什么相同对象被编译器确定为动态的。

标签: c# list dynamic


【解决方案1】:

This question 回答了为什么 sameObject 被编译器确定为 dynamic

一个更简单的例子来证明这一点:

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

AddIList 不起作用的原因似乎归结为重载决议。运行时在 IList 上找不到要使用的 Add 的重载,因此会引发异常。您已经知道,如果您明确说明它工作的类型,那么这可能是解决问题的方法。

有趣的是,如果您使用ICollection&lt;ClassA&gt;(如建议的here),它确实有效,所以这似乎是IList 接口的问题:

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

【讨论】:

  • 当使用 IListInsert 而不是 Add 时,它也可以工作。 Insert 直接在IList 中声明。因此,方法调用的运行时解析似乎找不到从另一个接口继承的接口中的方法,可能是因为接口继承不包括实现继承。
【解决方案2】:

我真的很想知道为什么使用“var sameObject”不起作用

您试图在IList 上拨打Add,这就是它不起作用的原因。您可以通过 2 种方式解决此问题:

修复 1

调用ToList(),然后添加对象。

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

修复 2

从您的财产返回List

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

【讨论】:

  • 这并不能解释为什么如果他们这样做ClassA sameObject = DoNothing(dynamicClassA) 它工作正常我认为这个问题的真正根源是为什么var 推断dynamic 而不是ClassA 作为类型sameObject
  • @JohnKoerner 不,它不会推断出动态。它推断ClassA
  • 根据VS IDE推断动态:imgur.com/zel8syF
  • 我的 VS IDE 显示 ClassA 就像我之前说的:imgur.com/a/pcN2T
  • 类型列为动态(看右列),值为ToString(),显示类名。
猜你喜欢
  • 1970-01-01
  • 2014-10-15
  • 2013-04-10
  • 2015-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-30
相关资源
最近更新 更多