C#中,“dynamic”和“object”关键字有什么区别?

6

有人能简要解释一下C#中“dynamic”和“object”关键字的区别吗?


2
你能否先做一些研究,而不是直接在这里提问呢?如果你在谷歌上搜索“C#中动态和对象的区别”,你会得到很多好的结果,包括之前提到的重复内容。 - educampver
3个回答

23

对象

首先,让我们快速了解一下“object”关键字。我不会过多地谈论它,因为它从C# 1.0开始就存在了。这个关键字只是System.Object的一个快捷方式,而System.Object是C#类层次结构中的根类型。(然而,正如Eric Lippert在他的博客文章中指出的那样,并不是所有的C#都派生自object。)这是一个强大的机制,因为你可以将几乎任何值分配给这种类型的实例。

下面是一个简短的示例,演示了使用“object”关键字的一些好处和问题。

object obj = 10;
Console.WriteLine(obj.GetType());
// Prints System.Int32 because 
// this is the type of the value stored in this object.

// A compiler error, because 
// at compile time the type of obj is System.Object.
// obj = obj + 10; 

// You need to explicitly cast obj to a necessary type.
obj = (int)obj + 10;

// However, this does not mean that you are really safe. 
// You can cast to a wrong type 
// and the compiler will not detect it. 
// Here you get an exception at run time, 
// because obj is an integer, not a string.
// obj = (string)obj + 10;

// You also get a run-time exception 
// if you cast to a wrong numeric type, 
// even if there is an implicit conversion in the language.
// obj = (double)obj + 10;

如您所见,虽然 obj 存储了一个整数,但编译器不允许您进行任何数学运算,除非进行强制转换。看起来像是强制转换可以帮助您确保您真的拥有一个整数,但事实并非如此。您可以将其转换为完全不同的类型,而编译器将无法检测到。结果是,您会得到一个运行时异常。
因此,您必须执行显式转换,这并不能保证任何东西,只是因为编译器不允许您在没有转换的情况下运行程序。 动态
这就是 C# 4.0 中新的 dynamic 关键字发挥作用的地方。它告诉编译器不要对您的代码强制执行额外的规则。
dynamic dyn = 10;
Console.WriteLine(dyn.GetType());
// Same as "object". 
// Prints System.Int32 because 
// this is the type of the value stored in this object.

// No compiler error, because 
// the compiler does not try to identify 
// the type of the dynamic object at compile time.
dyn = dyn + 10;

// Also, this operation will succeed for all numeric 
// or other types that support a “+” operation.
dyn = 10.0;
dyn = dyn + 10;

dyn = "10";
dyn = dyn + 10;

这是 object 和 dynamic 之间的一个主要区别 - 使用 dynamic,您告诉编译器对象的类型仅在运行时可知,并且编译器不会干涉。因此,您可以写更少的代码。我想强调的是,这并不比使用原始的 object 关键字更危险。但是,它也不比原始关键字更安全,因此在处理动态对象时必须使用所有类型检查技术(例如反射)。
接下来经常出现的问题是:“由于动态对象可以是任何东西,编译器不会检查它是什么,这是否意味着您可以将动态对象传递给我的方法/系统并使其崩溃?”
假设我们有一个简单的方法。
public static void Print(string arg)
{
    Console.WriteLine(arg);
}
Now let’s look at how you can pass a dynamic object to it.

dynamic dyn = 10;

// You get an exception at run time here.
Print(dyn);

可以看到,尽管编译器允许您将动态对象传递给方法,但如果它的类型不正确,则该方法永远不会得到此对象。在实际调用方法之前,会抛出异常。唯一的方法是,如果动态对象包含必要的值,即字符串,才能将其传递给您的方法。

dynamic dyn = "10";
Print(dyn);

再次强调,这与使用"object"关键字的行为并没有太大区别。

object obj = 10;

// Doesn't compile.
//Print(obj);

// Compiles, but there is an exception at run time.
//Print((string)obj);

// This code works because obj is now a string, 
// but you still need a cast.
obj = "10";
Print((string)obj);

有些人认为读取(int)obj不难,所以为什么要使用dynamic呢?但是,在进行许多类型转换操作时,您的代码几乎变得难以阅读。还有一些情况下,简单的类型转换是不够的,您需要调用反射方法,例如InvokeMember或GetProperties。其中一个很好的例子是COM互操作性,这就是为什么修改后使用了新的dynamic功能(有关更多信息,请查看此“how-to”)。
此外,dynamic关键字和动态语言运行时使许多以前不可能或困难的场景成为可能,包括与动态语言的互操作性。我之前在博客中强调了一些这样的情况:介绍ExpandoObject和使用DynamicObject创建包装器。
结论是,没有必要担心使用dynamic功能会破坏您的代码。它不比object关键字更危险(也不更安全)。
因此,如果经常使用object关键字并且必须执行大量强制类型转换和/或使用反射调用对象的方法和属性,则可能应该查看dynamic关键字。在某些情况下,它比object更方便,并且需要编写的代码更少。

7
请查看Anders Hejlsberg的演讲,以更好地理解动态特性。
另请查看此页面上的C#关键字。
这些关键字指的是.NET常见类型。
基本上: object类型是.NET Framework中Object的别名。 在C#的统一类型系统中,所有类型(预定义和用户定义,引用类型和值类型(包括动态类型))都直接或间接继承自Object。 您可以将任何类型的值分配给类型为对象的变量。
谈到动态类型:
动态类型使其出现的操作可以绕过编译时类型检查。 相反,这些操作在运行时解决。 动态类型简化了对COM API(例如Office Automation API),动态API(例如IronPython库)和HTML文档对象模型(DOM)等的访问。

类型 dynamic 在大多数情况下的行为类似于类型 object。但是,包含类型为 dynamic 的表达式的操作不会被编译器解析或类型检查。编译器将有关操作的信息打包在一起,该信息稍后用于在运行时评估操作。作为此过程的一部分,类型为 dynamic 的变量被编译成类型为 object 的变量。因此,类型 dynamic 仅存在于编译时,而不是运行时。

请注意,此说明摘自 MSDN 页面。


1
  • object 恰恰就是那样:一个纯粹的 C# 对象,只有最少量的方法。在 .NET 中,它作为一切事物的内置基类(确保每个对象都至少拥有 ToString()Equals()GetHashCode())。
  • 相比之下,dynamic 对象则完全不同。在静态类型语言中,dynamic 允许延迟绑定属性和方法,带来了一些能力和更好的兼容性,例如动态类型语言 Python。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接