对象之间的区别a = new Dog()vs Dog a = new Dog()

时间:2011-12-19 02:51:47

标签: c# object new-operator

object a = new Dog();

VS

Dog a = new Dog();

在这两种情况下,a.GetType()都会Dog。 两者都调用相同的构造函数(具有相同的层次结构)。

那么请你告诉我这两个陈述之间的区别吗?

6 个答案:

答案 0 :(得分:36)

两者都创建一个Dog对象。只有第二个允许您直接调用Dog方法或以其他方式将其视为狗,例如,如果您需要将对象作为Dog类型的参数传递给方法(或者Dog层次结构中的某些内容)更具体而不仅仅是object)。

object obj = new Dog(); 
// can only see members declared on object
var type = obj.GetType(); // can do this
Console.WriteLine(obj.ToString()); // also this
obj.Bark(); // Error! Bark is not a member of System.Object

Dog dog = new Dog();
// can do all of the methods declared for Object
dog.Bark(); // can finally use the method defined for Dog

答案 1 :(得分:6)

new Dog()是一个创建新Dog实例的表达式。它调用Dog类的无参数构造函数。

a是一个变量:内存中的存储单元,在分配后保存对Dog实例的引用。

不同之处在于Dog变量只能保存对Dog实例(或从Dog派生的任何类的实例)的引用,而object变量可以保存对object实例的引用(或者是object派生的任何类的实例 - Dog类的实例)。

如果有Dog变量,则可以在引用的实例上调用Dog类(及其基类)定义的任何方法。如果有object变量,则只能在实例上调用object类的方法。

答案 2 :(得分:5)

您的第一行创建了object类型的变量

编译器不允许您将其视为Dog

答案 3 :(得分:5)

两个语句都包含声明和构造函数调用。构造函数的调用是相同的,因此在两种情况下都会得到Dog。声明是不同的:在第一种情况下,您声明一个object类型的变量,一个超级类Dog;在第二种情况下,您声明一个类型为Dog的变量。不同之处在于,在后续代码中,只有在将变量声明为Dog时,才能调用Dog的方法而不进行强制转换。如果你将其声明为object,则需要演员。

答案 4 :(得分:4)

两个语句都涉及调用Dog的默认构造函数,如你自己提到的那样;因此,显然在两种情况下都构造了Dog实例。这意味着两个语句最终使用相同的实例初始化变量(这是等于后的语句的一部分)。

但是,这些语句还有另一部分:变量的声明(这是等于之前语句的一部分)。在诸如C#的静态类型语言中,每个变量 - 更一般地说,任何表达式 - 都具有静态类型:

object a = new Dog(); // static type: object / runtime type: Dog
Dog b = new Dog();    // static type: Dog / runtime type: Dog

编译器不允许您为变量分配值,它不能证明属于变量的静态类型,例如它不允许

Cat c = new Dog(); // unless Dog derives from Cat, which we know isn't true

由于所有 reference types 都隐式派生自System.Object,因此将Dog分配给静态类型object的变量即可。 您可以将“静态类型”视为对象“声明为”的内容。您只需通过阅读源代码即可确定的静态类型;这就是编译器的工作方式。

然后还有每个变量(表达式)的运行时类型,我在上面提到过。这两种情况都是一样的,因为毕竟在这两种情况下我们都创建了Dog您可以将“运行时类型”视为对象实际 只能通过读取源来确定某些内容的运行时类型;您只在程序运行时确定它,因此名称。在C#中,这是通过调用GetType来完成的。

很明显,运行时类型是你不能没有的东西¹;毕竟所有必须“成为”某事。但为什么要发明静态类型的概念呢?

您可以将static types视为您(程序员)与编译器之间的契约。通过将b的静态类型声明为Dog,您告诉编译器您不打算使用该变量来存储除Dog之外的任何内容。作为回报,编译器承诺不会让您违反您声明的目的,并且如果您尝试这样做会产生错误。它还会阻止您以任何 类型d应支持的方式使用Dog

考虑:

class Dog {
    public void Woof();
}

Dog d = new Dog();
d.Woof(); // OK

object o = new Dog();
o.Woof(); // COMPILER ERROR

最后一行导致编译器错误,因为它违反了静态类型契约:你告诉编译器o可以是从System.Object派生的任何东西,但并非所有源自它的东西都有方法Woof。所以编译器试图通过说“你在那里做什么来保护你?我不能证明o中的任何东西都可以了!如果它是Cat怎么办?”。

注意:

¹这并不意味着每个对象都神奇地知道它在所有语言中的含义。在某些情况下(例如在C ++中),这些信息可能在创建对象时使用,但随后被“遗忘”,以便编译器可以更自由地优化代码。如果发生这种情况,对象仍然 ,但你不能戳它并问它“你是什么?”。

²实际上,在这个琐碎的例子中,它可以证明这一点。但它不会选择使用这些知识,因为尊重静态类型的契约就是重点。

答案 5 :(得分:2)

当您想要使用多态时,这很有用,您可以使用在Dog中实现的抽象方法。因此,这样对象就是Dog,即使是Object也是如此。因此,当您想使用多态时,可以使用这种方式。