【问题标题】:List<Object> vs List<dynamic>列表<对象> 与列表<动态>
【发布时间】:2012-05-09 22:24:05
【问题描述】:

我需要创建一个异构的List 对象(自定义类)。我的第一个想法是创建一个List&lt;ISomeMarkerInterface&gt;,但我很快了解到这不是我想要的。我的下一个想法是List&lt;dynamic&gt;,这似乎不是一个坏主意。但是,我正在做一些研究并遇到了这个article about boxing and unboxing,在这个例子中,他们基本上正在做我想要使用List&lt;Object&gt; 做的事情。

除了dynamic 将在运行时评估而Object 在编译时评估之外,List&lt;dynamic&gt;List&lt;Object&gt; 之间有什么区别?它们本质上不是一样的吗?

【问题讨论】:

  • 为什么需要将异构对象存储在同一个列表中?只是好奇...
  • 你应该寻找 dynamic vs object ,看看这个帖子,它可能会回复你的答案stackoverflow.com/questions/3442821/dynamic-vs-object-type
  • 我有一个类,其中一个属性是与该类相关的项的集合,这些项的类型不同,但作为一个组相关。
  • 顺便说一句,你能解释一下为什么ISomeMarkerInterface不好?
  • 如果您想要的只是简单的 LINQ,您是否看过 Enumerable.OfType() 和 Listmsdn.microsoft.com/en-us/library/bb360913.aspx

标签: c# asp.net


【解决方案1】:

不同之处在于,如果您使用 object 并尝试访问 object 的某些成员,则会出现编译时错误(因为 object 没有此成员)。为了工作,您需要知道类型是什么并进行转换。

使用动态您可以访问任何成员 - 没有编译时错误。如果该成员在运行时不存在,则将是运行时错误。例如,如果你知道你的异端对象都具有相同的成员,那么这是要走的路。

但是,如果是这种情况,还有另一个更清晰的解决方案:您可以使用此成员定义一个接口,然后让您的所有异质对象实现它,您的列表可以是List&lt;IYourInterface&gt;

请记住,动态的性能可能会稍差,因为动态类型解析。

【讨论】:

  • 使用动态,你能检查一个成员的存在,如果它不存在就继续而不抛出错误吗?有点像在 javascript 中你怎么能做类似if (data.something) {}?
  • 这称为反射。您可以在有或没有 dynamic 的情况下使用它。查看 GetType()、GetMethod() 等。
  • +1,如果你沿着反射路线走,你还不如只使用 Object (但我仍然建议在此之上使用标记接口)
【解决方案2】:

C# 中有 3 种“通用”类型(尽管并非全部都是真实类型):object、var 和 dynamic。

对象

一个实际的类型,和任何其他类型一样,有一个特殊的规则:如果一个类型不继承,它继承自object。由此可见,所有类型直接或间接地继承自object

强调:对象是一种类型。一个对象可以是 object 类型,并且该类型有它的方法,例如 ToString()。由于一切都继承自 object,因此一切都可以向上转换为 object。当您将一个对象分配给一个 object 引用时,就像您将一个 Elephant 类型的对象分配给一个 Animal 引用一样,您正在进行向上转换,其中 Elephant 继承自 Animal

SomeType x = new SomeType();
object obj = x;
obj.DoSomething();
  • obj 在编译时被视为 object 类型,在运行时将是 object 类型(这是合乎逻辑的,因为它是实际类型 - obj 被声明为 object 所以只能是那个类型)
  • obj.DoSomething() 会导致编译时错误,因为 object 没有这个方法,不管 SomeType 有没有。

变量

这不是一个实际的类型,它只是“编译器,根据赋值右侧为我找出类型”的简写。

SomeType x = new SomeType();
var obj = x;
obj.DoSomething();
  • obj 在编译时被视为 SomeType 类型,在运行时将是 SomeType 类型,就像你写了“SomeType " 而不是 "var"。
  • 如果SomeType有一个方法DoSomething(),这段代码就可以工作
  • 如果SomeType没有方法,代码会导致编译时错误

动态

这是一种告诉编译器禁用对变量的编译时类型检查的类型。对象在编译时和运行时被视为具有 dynamic 类型。

SomeType x = new SomeType();
dynamic obj = x;
obj.DoSomething();
  • obj 在编译和运行时属于 dynamic 类型
  • 如果SomeType有一个方法DoSomething(),这段代码就可以工作
  • 如果SomeType没有方法,代码会编译,但在运行时抛出异常
  • 注意动态如果使用不慎很容易引发异常:

    public void f(dynamic x)
    { 
        x.DoSomething();
    }
    

如果 x 属于没有 DoSomething 方法的类型,这将引发异常,但仍然可以调用它并传递任何对象作为没有编译时错误的参数,导致仅在运行时显示的错误,并且可能仅在特定情况下显示 - 一个潜在的错误。因此,如果您在类的任何类型的公共接口中使用动态,您应该始终在运行时使用反射手动进行类型检查,小心处理异常,或者一开始就不要这样做。

注意:当然,被引用的对象永远不会改变它的类型。虽然 obj 可能是 object,但它所指的 x 仍然是 SomeType

【讨论】:

  • -1 表示dynamic 不是实际类型(与var 非常不同,正如您所说的那样,它不是 实际类型)。 dynamic 绝对是 C# 中的一种类型,它甚至是 static 类型,但 dynamic 类型的对象将绕过静态类型检查。查看 C# 语言规范的 §4.7 或此链接 (msdn.microsoft.com/en-us/library/dd264736.aspx) 了解更多信息。
  • 糟糕,我修好了。我想我应该先检查一下。 :D 虽然动态在分配运行时立即被解析为适当的类型,并且从未真正键入为“动态”,但显然情况并非如此。
  • 对了,如果遇到"missing compiler required member"编译错误,需要添加对Microsoft.CSharp.dll的引用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-22
  • 1970-01-01
  • 2020-06-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多