【问题标题】:Object assignment in C#C#中的对象赋值
【发布时间】:2013-12-07 12:54:05
【问题描述】:

这是我在使用 C# IList 集合时遇到的问题

IList<MyClass> foo = new List<MyClass>();
var bar = new List<MyClass>();

foo.AddRange() // doesn't compile
bar.AddRange() // compile

据我所知,在 C#(与 C++ 相反)中,当我们使用这种语法创建对象时,对象类型获取右侧(赋值)而不是左侧(声明)。

我错过了什么吗?

EDIT

我还是不明白,即使在你的回答之后, foo 和 bar 有相同的类型!

【问题讨论】:

  • "var" 属于 List 类型,它具有“AddRange”方法,而 foo 属于 IList 类型,它是一个没有“AddRange”方法的接口。
  • 但是它们都被实例化为 List 类型
  • @Schneider 确实如此,但从编译器的角度来看,foo 的类型是 IList&lt;&gt; 而不是 List&lt;&gt;
  • 是的,但您将一个变量 (foo) 隐式转换为 IList
  • 重点是你创建的对象是List类型的,而你用来引用它的变量却不是。

标签: c# object variable-assignment


【解决方案1】:

这里没有这么微妙的事情发生:

  • foo 的类型为 IList&lt;MyClass&gt;,而 IList&lt;T&gt; 没有 AddRange 方法
  • bar 的类型为List&lt;MyClass&gt;,而List&lt;T&gt; 确实有一个AddRange 方法。

就是这样。在 C++ 中也是如此。

更新:在编辑中,您正在调用 GetType(),它获取对象的运行时类型 - 在编译时编译器正在查看 foo 和 bar 变量的静态类型。

想想Object myObj = "MyString" 可能会让事情变得更清楚,因为“对象”和“字符串”之间存在更明显的区别,即使它们与 IList 和 List 具有相同的继承关系

【讨论】:

    【解决方案2】:

    问题是你使用的接口和IList没有AddRange但是ListAddRange

    如果你改成

    List<MyClass> foo = new List<MyClass>();
    

    它会起作用的。因为它有这个方法。

    这是IList 所拥有的

    你也可以这样做

    IEnumerable<MyClass> foo = new List<MyClass>();
    

    你会发现这对它的限制更大

    为您的编辑编辑:

    它们都是同一类型,因为它们仍然是Lists。不同之处在于您使用的变量。通过使用接口,您将操作限制在接口支持的范围内。由于List 实现了IListIList 具有List 具有的操作子集。

    底层对象仍然是List

    【讨论】:

      【解决方案3】:

      foo 的底层类型是 List,但编译器用来确保正确性的静态类型是 IList&lt;T&gt;。您在 foo 上调用的任何内容都必须声明为 IList&lt;T&gt; 类型的一部分。

      【讨论】:

        【解决方案4】:

        试试:

        List<MyClass> foo = new List<MyClass>(); // CHANGED TO List<> rather than IList<>
        var bar = new List<MyClass>();
        
        foo.AddRange() // doesn't compile
        bar.AddRange() // compile
        

        【讨论】:

          【解决方案5】:

          此外,IList 声明了一种行为,而不是具体类型。请看这里

          http://msdn.microsoft.com/en-us/library/system.collections.ilist%28v=vs.110%29.aspx

          在一个List中可以添加item,IList类型是已经构造好的类型,实现了这个接口。

          【讨论】:

            【解决方案6】:

            我没有理解你的问题,但在这种情况下,C# 和 C++ 的行为方式相同。在您的示例中,为了提供可以编译的代码,您可以编写

            IList<MyClass> foo = new List<MyClass>();
            var bar = new List<MyClass>();
            
            ( (List<MyClass> )foo ).AddRange(); 
            bar.AddRange() // compile
            

            其实它和 C++ 中的 dynamic_cast 是一样的意思。

            【讨论】:

              【解决方案7】:

              正如大家所说的 IList 不支持 AddRange,它也不需要支持它。

              您可以:

              1 ) ((List<MyClass>)foo).AddRange(anotherList);
              2 ) You can also use extension method to AddRange
              3 ) There are another workarounds for this problem e.g. Concat etc.
              

              我也认为,接口在某些时候不应该支持类上的每个函数,这应该基于接口隔离原则

              【讨论】:

                猜你喜欢
                • 2013-11-24
                • 2014-12-04
                • 1970-01-01
                • 1970-01-01
                • 2017-11-07
                • 1970-01-01
                • 1970-01-01
                • 2012-08-04
                • 1970-01-01
                相关资源
                最近更新 更多