C#中“动态”和“对象”关键字有什么区别?

时间:2014-01-08 12:32:29

标签: .net c#-4.0

有人能简单解释一下C#中“动态”和“对象”关键词之间的区别吗?

3 个答案:

答案 0 :(得分:10)

对象

我们先来看看object关键字。我不打算谈论它,因为它自C#1.0以来一直存在。此关键字只不过是System.Object的快捷方式,System.Object是C#类层次结构中的根类型。 (但正如Eric Lippert在他的博客文章中所指出的,并非C#中的所有内容都来自于对象。)这是一种强大的机制,因为您几乎可以为此类实例分配任何值。

这是一个简短的示例,演示了使用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 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;

这是对象和动态之间的主要区别之一 - 使用动态,您告诉编译器只能在运行时知道对象的类型,并且编译器不会尝试干扰。因此,您可以编写更少的代码。我想强调的是,这并不比使用原始对象关键字更危险。但是,它也没有那么危险,所以在操作对象时需要使用的所有类型检查技术(例如反射)也必须用于动态对象。

经常出现的下一个问题如下:“由于动态对象可以是任何东西而编译器不检查它是什么,这是否意味着您可以将动态对象传递给我毫无疑问的方法/系统让它崩溃?“

我们假设我们有一个简单的方法。

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并不难,所以为什么要费心去做?好吧,在某些情况下,您必须执行如此多的强制转换操作,这会使您的代码几乎无法读取。在某些情况下,简单的强制转换是不够的,您必须调用反射方法,例如InvokeMember或GetProperties。这里有一个很好的例子是COM互操作,这就是为什么它被修改为使用新的动态功能(更多信息,请看这个“操作方法”。)

此外,动态关键字和动态语言运行库支持许多以前不可能或很难做到的场景,包括与动态语言的互操作。我在此博客前面已经强调了几个这样的场景:介绍ExpandoObject和使用DynamicObject创建Wrappers。

结论

结论是,没有必要担心有人可以通过使用动态功能来破坏您的代码。与object关键字相比,它不再(并且再次,同样)危险。

因此,如果您经常使用object关键字并且必须执行大量的转换和/或使用反射来调用对象的方法和属性,那么您可能应该查看dynamic关键字。在某些情况下,它比对象更方便,编写的代码更少。

答案 1 :(得分:7)

请查看Anders Hejlsberg的this演讲,以便更好地了解动态。

另请在此页面上查看C# keywords

这些关键字指的是.NET常见类型。

基本上: 对象类型是.NET Framework中Object的别名。在C#的统一类型系统中,所有类型,预定义和用户定义的引用类型和值类型(包括动态)直接或间接地从Object继承。您可以将任何类型的值分配给object类型的变量。

谈论动态

动态类型使其发生的操作可以绕过编译时类型检查。相反,这些操作在运行时解决。动态类型简化了对COM API(如Office Automation API)以及动态API(如IronPython库)和HTML文档对象模型(DOM)的访问。

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

请注意,此解释取自MSDN页面。

答案 2 :(得分:1)

  • object就是这样:一个简单的C#对象,只有最少的方法。在.NET中,它作为所有内容的内置基类(确保所有内容至少包含ToString()Equals()GetHashCode())。
  • 相反,
  • dynamic对象是完全不同的品种。 dynamic允许以其他静态类型语言对道具和方法进行后期绑定 - 带来一些能力和与动态类型语言的更好兼容性,例如:蟒。