我需要创建异构List
个对象(自定义类)。我的第一个想法是创建一个List<ISomeMarkerInterface>
但我很快就知道这不是我想要的。我的下一个想法是List<dynamic>
,这似乎并不是一个坏主意。但是,我正在做一些研究并遇到了这个article about boxing and unboxing,在这个例子中,他们基本上正在使用List<Object>
做我想做的事情。
除了dynamic
将在运行时和Object
在编译时进行评估,List<dynamic>
和List<Object>
之间的区别是什么? Aren他们基本上是一回事吗?
答案 0 :(得分:23)
C#中有3种“通用”类型(尽管不是全部都是真实类型):object,var和dynamic。
<强>对象强>
实际类型,与任何其他类型一样,具有一个特殊规则:如果某个类型未继承,则它继承自 object 。由此可见,所有类型直接或间接地从对象继承。
重点:对象是一种类型。对象可以是 object 类型,类型有其方法,如ToString()。由于所有内容都继承自 object ,因此所有内容都可以转换为 object 。当您将对象分配给对象引用时,您正在进行向上转换,就像将 Elephant 类型对象分配给 Animal 引用一样< em> Elephant 继承自 Animal 。
SomeType x = new SomeType();
object obj = x;
obj.DoSomething();
<强>无功强>
这不是一个实际的类型,它只是“编译器的简写,根据赋值的右侧为我找出类型”。
SomeType x = new SomeType();
var obj = x;
obj.DoSomething();
<强>动态强>
这是一种告诉编译器禁止对变量进行编译时类型检查的类型。在编译时和运行时将对象视为具有 dynamic 类型。
SomeType x = new SomeType();
dynamic obj = x;
obj.DoSomething();
请注意,如果不小心使用,动态会非常容易导致异常:
public void f(dynamic x)
{
x.DoSomething();
}
如果 x 属于没有 DoSomething 方法的类型,则会抛出异常,但仍然可以调用它并传递任何对象作为没有编译时错误的参数,导致错误仅在运行时显示,并且可能仅在特定情况下显示 - 潜在的错误。因此,如果在类的任何类型的公共接口中使用dynamic,则应始终使用反射在运行时手动键入 - 检查,小心处理异常,或者不首先执行此操作。
注意:被引用的对象当然不会改变其类型。虽然 obj 可能是对象,但它引用的 x 仍然是 SomeType 。
答案 1 :(得分:2)
不同之处在于,如果您使用对象并尝试访问对象的某个成员,则会出现编译时错误(因为对象没有此成员)。为了工作,你需要知道什么是类型并投下它。
使用动态,您可以访问任何成员 - 没有编译时错误。如果成员在运行时不存在,那将是运行时错误。如果您知道您的所有对象都具有相同的成员,那么这就是你要走的路。
但是,如果是这种情况,还有另一个更明确的解决方案:您可以使用此成员定义一个接口,然后让所有您的同等对象实现它,您的列表可以是List<IYourInterface>
。
请记住,由于动态类型分辨率很高,动态性能可能会稍微差一些。