Разница между объектом a = new Dog() vs Dog a = new Dog()

object a = new Dog();

против

Dog a = new Dog();

В обоих случаях a.GetType() дает Dog. Оба ссылаются на тот же конструктор (с той же иерархией).

Тогда, пожалуйста, скажите мне разницу между этими двумя утверждениями?

Ответы

Ответ 1

Оба создают объект 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

Ответ 2

new Dog() - это выражение, которое создает новый экземпляр Dog. Он вызывает безразмерный конструктор класса Dog.

a - это переменная: ячейка памяти в памяти, которая содержит ссылку на экземпляр Dog после назначения.

Разница в том, что переменная Dog может содержать только ссылку на экземпляр Dog (или экземпляр любого класса, который происходит от Dog), в то время как переменная object может содержать ссылку на object экземпляр (или экземпляр любого класса, который выводится из object), который имеет класс Dog).

Если у вас есть переменная Dog, вы можете вызвать любой метод, определенный классом Dog (и его базовые классы) в ссылочном экземпляре. Когда у вас есть переменная object, вы можете вызывать только методы класса object в экземпляре.

Ответ 3

Ваша первая строка создает переменную типа object.

Компилятор не позволит вам рассматривать это как Dog.

Ответ 4

Оба оператора содержат объявление и вызов конструктора. Вызовы конструктора идентичны, поэтому вы получаете Dog в обоих случаях. Объявления различны: в первом случае вы объявляете переменную типа object, суперкласс из Dog; во втором случае вы объявляете переменную типа Dog. Разница в том, что в следующем коде вы можете вызывать методы Dog без приведения только тогда, когда вы объявляете переменную как Dog; если вы объявите его как object, вам понадобится бросок.

Ответ 5

Оба оператора включают вызов конструктора по умолчанию Dog, как вы сами указываете; поэтому очевидно, что в обоих случаях создается экземпляр Dog. Это означает, что оба оператора завершают инициализацию переменной с идентичным экземпляром (это является частью инструкции после равных).

Однако в операторах также есть другая часть: объявление переменной (это часть выражения перед равными). В статически типизированных языках, таких как С#, каждая переменная - в общем, любое выражение - имеет статический тип:

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

Поскольку все ссылочные типы неявно вытекают из System.Object, присвоение переменной Dog переменной статического типа object ОК. Вы можете думать о "статическом типе" как о том, что объект "объявлен как". Вы всегда можете определить статический тип чего-либо, просто прочитав исходный код; это то, как это делает компилятор.

Затем также существует тип среды выполнения каждой переменной (выражение), о которой я говорил выше. В обоих случаях это одно и то же, потому что в обоих случаях мы создали Dog. Вы можете думать о "типе времени выполнения" как о том, что на самом деле представляет собой объект. Тип времени выполнения не может быть определен только путем чтения источника; вы определяете его только во время работы программы, отсюда и название. В С# это делается путем вызова GetType.

Должно быть очевидно, что тип времени выполнения - это то, что вы не можете сделать без 1; все должно "быть" в конце концов. Но зачем беспокоиться о том, чтобы изобрести понятие статического типа?

Вы можете думать о статических типах в качестве контракта между вами (программистом) и компилятором. Объявив статический тип b Dog, вы сообщаете компилятору, что вы не собираетесь использовать эту переменную для хранения чего-либо иного, кроме Dog. Компилятор, в свою очередь, promises, чтобы вы не нарушили заявленную цель и не сделали ошибку, если попытаетесь это сделать. Это также предотвращает использование 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, может woof! Что, если это был Cat?".

Примечания:

¹ Это не означает, что каждый объект волшебным образом знает, что он "есть" на всех языках. В некоторых случаях (например, в С++) эта информация может использоваться при создании объекта, но затем "забывается", чтобы позволить компилятору больше свободы для оптимизации кода. Если это произойдет, объект все еще есть что-то, но вы не можете его высунуть и спросить его "кто вы?".

² На самом деле, в этом тривиальном примере это может доказать. Но он не захочет использовать эти знания, потому что соблюдение контракта статического типа - это целая точка.

Ответ 6

Это полезно, если вы хотите использовать полиморфизм, и вы можете использовать абстрактный метод, который реализуется в Dog. Следовательно, таким образом объект является Собакой, даже так есть Object. Поэтому вы можете использовать этот способ, когда хотите использовать полиморфизм.