В мире .NET Core каждый тип в конечном итоге является производным от базового класса по имени System.Object, который в языке C# может быть представлен с помощью ключевого слова object (с буквой о в нижнем регистре). Класс Object определяет набор общих членов для каждого типа внутри платформы. По сути, когда вы строите класс, в котором явно не указан родительский класс, компилятор автоматически делает его производным от Object. Если вы хотите прояснить свои намерения, то можете определять классы, производные от Object, следующим образом (однако вы не обязаны поступать так):

// Явное наследование класса от System.Object.

class Car : object

{...}

Подобно любому классу в System.Object определен набор членов. В показанном ниже формальном определении C# обратите внимание, что некоторые члены объявлены как virtual, указывая на возможность их переопределения в подклассах, тогда как другие помечены ключевым словом static (и потому вызываются на уровне класса):

public class Object

{

  // Виртуальные члены.

  public virtual bool Equals(object obj);

  protected virtual void Finalize();

  public virtual int GetHashCode();

  public virtual string ToString();

  // Невиртуальные члены уровня экземпляра.

  public Type GetType();

  protected object MemberwiseClone();

  // Статические члены.

  public static bool Equals(object objA, object objB);

  public static bool ReferenceEquals(object objA, object objB);

}

В табл. 6.1 приведен обзор функциональности, предоставляемой некоторыми часто используемыми методами System.Object.

Чтобы проиллюстрировать стандартное поведение, обеспечиваемое базовым классом Object, создайте новый проект консольного приложения C# по имени ObjectOverrides.

Добавьте в проект новый файл класса С#, содержащий следующее пустое определение типа Person:

// Не забывайте, что класс Person расширяет Object.

class Person {}

Теперь обновите операторы верхнего уровня для взаимодействия с унаследованными членами System.Object:

Console.WriteLine("***** Fun with System.Object *****\n");

Person p1 = new Person();

// Использовать унаследованные члены System.Object.

Console.WriteLine("ToString: {0}", p1.ToString());

Console.WriteLine("Hash code: {0}", p1.GetHashCode());

Console.WriteLine("Type: {0}", p1.GetType());

// Создать другие ссылки на pi.

Person p2 = p1;

object o = p2;

// Указывают ли ссылки на один и тот же объект в памяти?

if (o.Equals(p1) && p2.Equals(o))

{

  Console.WriteLine("Same instance!");

}

Console.ReadLine();

}

Вот вывод, получаемый в результате выполнения этого кода:

***** Fun with System.Object *****

ToString: ObjectOverrides.Person

Hash code: 58225482

Type: ObjectOverrides.Person

Same instance!

Обратите внимание на то, что стандартная реализация ToString() возвращает полностью заданное имя текущего типа (ObjectOverrides.Person). Как будет показано в главе 15, где исследуется построение специальных пространств имен, каждый проект C# определяет "корневое пространство имен", название которого совпадает с именем проекта. Здесь мы создали проект по имени ObjectOverrides, поэтому тип Person и класс Program помещены внутрь пространства имен ObjectOverrides.

Перейти на страницу:

Похожие книги