Типы и элементыTypes and members

Классы и объектыClasses and objects

Классы являются основным типом в языке C#.Classes are the most fundamental of C#’s types. Класс представляет собой структуру данных, которая объединяет в себе значения (поля) и действия (методы и другие функции-члены).A class is a data structure that combines state (fields) and actions (methods and other function members) in a single unit. Класс предоставляет определение для экземпляров класса, которые также именуются объектами.A class provides a definition for instances of the class, also known as objects. Классы поддерживают механизмы наследования и полиморфизма, которые позволяют создавать производные классы, расширяющие и уточняющие определения базовых классов.Classes support inheritance and polymorphism, mechanisms whereby derived classes can extend and specialize base classes.

Новые классы создаются с помощью объявлений классов.New classes are created using class declarations. Объявление класса начинается с заголовка.A class declaration starts with a header. Заголовок указывает:The header specifies:

  • Атрибуты и модификаторы классаThe attributes and modifiers of the class
  • Имя классаThe name of the class
  • Базовый класс (при наследовании от базового класса)The base class (when inheriting from a base class)
  • Интерфейсы, реализуемые классом.The interfaces implemented by the class.

За заголовком между разделителями { и } следует тело класса, в котором последовательно объявляются все члены класса.The header is followed by the class body, which consists of a list of member declarations written between the delimiters { and }.

Следующий код является простым примером объявления класса с именем Point:The following code shows a declaration of a simple class named Point:

public class Point
{
    public int X { get; }
    public int Y { get; }
    
    public Point(int x, int y) => (X, Y) = (x, y);
}

Экземпляры классов создаются с помощью оператора new, который выделяет память для нового экземпляра, вызывает конструктор для инициализации этого экземпляра и возвращает ссылку на экземпляр.Instances of classes are created using the new operator, which allocates memory for a new instance, invokes a constructor to initialize the instance, and returns a reference to the instance. Следующие инструкции создают два объекта Point и сохраняют ссылки на эти объекты в двух переменных:The following statements create two Point objects and store references to those objects in two variables:

var p1 = new Point(0, 0);
var p2 = new Point(10, 20);

Занимаемая объектом память автоматически освобождается, когда объект становится недоступен.The memory occupied by an object is automatically reclaimed when the object is no longer reachable. В C# нет ни необходимости, ни возможности освобождать память объектов явным образом.It's neither necessary nor possible to explicitly deallocate objects in C#.

Параметры типаType parameters

Универсальные классы определяют *параметры типа _.Generic classes define *type parameters _. Параметры типа — это список имен параметров типа, заключенных в угловые скобки.Type parameters are a list of type parameter names enclosed in angle brackets. Параметры типа следуют за именем класса.Type parameters follow the class name. Параметры типа можно использовать в теле класса в определениях, описывающих члены класса.The type parameters can then be used in the body of the class declarations to define the members of the class. В следующем примере для класса Pair заданы параметры типа TFirst и TSecond:In the following example, the type parameters of Pair are TFirst and TSecond:

public class Pair<TFirst, TSecond>
{
    public TFirst First { get; }
    public TSecond Second { get; }
    
    public Pair(TFirst first, TSecond second) => 
        (First, Second) = (first, second);
}

Тип класса, для которого объявлены параметры типа, называется _универсальным типом класса*.A class type that is declared to take type parameters is called a _generic class type*. Типы структуры, интерфейса и делегата также могут быть универсальными.Struct, interface, and delegate types can also be generic. Если вы используете универсальный класс, необходимо указать аргумент типа для каждого параметра типа, вот так:When the generic class is used, type arguments must be provided for each of the type parameters:

var pair = new Pair<int, string>(1, "two");
int i = pair.First;     // TFirst int
string s = pair.Second; // TSecond string

Универсальный тип, для которого указаны аргументы типа, как Pair<int,string> в примере выше, называется сконструированным типом.A generic type with type arguments provided, like Pair<int,string> above, is called a constructed type.

базовых классов;Base classes

В объявлении класса может быть указан базовый класс.A class declaration may specify a base class. Имя базового класса указывается после имени класса и параметров типа и отделяется от них двоеточием.Follow the class name and type parameters with a colon and the name of the base class. Если спецификация базового класса не указана, класс наследуется от типа object.Omitting a base class specification is the same as deriving from type object. В следующем примере Point3D имеет базовый класс Point.In the following example, the base class of Point3D is Point. В первом примере Point имеет базовый класс object:From the first example, the base class of Point is object:

public class Point3D : Point
{
    public int Z { get; set; }
    
    public Point3D(int x, int y, int z) : base(x, y)
    {
        Z = z;
    }
}

Класс наследует члены базового класса.A class inherits the members of its base class. Наследование означает, что класс неявно содержит почти все элементы базового класса.Inheritance means that a class implicitly contains almost all members of its base class. Класс не наследует экземпляры, статические конструкторы и метод завершения.A class doesn't inherit the instance and static constructors, and the finalizer. Производный класс может добавлять новые члены к наследуемым, но не может удалить определение для наследуемого члена.A derived class can add new members to those members it inherits, but it can't remove the definition of an inherited member. В предыдущем примере Point3D наследует члены X и Y из Point, и каждый экземпляр Point3D содержит три свойства: X, Y и Z.In the previous example, Point3D inherits the X and Y members from Point, and every Point3D instance contains three properties, X, Y, and Z.

Используется неявное преобразование из типа класса к любому из типов соответствующего базового класса.An implicit conversion exists from a class type to any of its base class types. Переменная типа класса может ссылаться как на экземпляр этого класса, так и на экземпляры любого производного класса.A variable of a class type can reference an instance of that class or an instance of any derived class. Например, если мы используем описанные выше объявления классов, то переменная типа Point может ссылаться на Point или Point3D:For example, given the previous class declarations, a variable of type Point can reference either a Point or a Point3D:

Point a = new Point(10, 20);
Point b = new Point3D(10, 20, 30);

СтруктурыStructs

Классы определяют типы, поддерживающие наследование и полиморфизм.Classes define types that support inheritance and polymorphism. Они позволяют создавать сложные расширения функциональности на основе иерархий производных классов.They enable you to create sophisticated behaviors based on hierarchies of derived classes. В отличие от них, типы *struct _ — это простые типы, основное назначение которых — хранить значения данных.By contrast, *struct _ types are simpler types whose primary purpose is to store data values. В структурах не может быть объявлен базовый тип; они неявно наследуются от System.ValueType.Structs can't declare a base type; they implicitly derive from System.ValueType. От типа struct не могут быть унаследованы другие типы struct.You can't derive other struct types from a struct type. Они неявно запечатаны.They're implicitly sealed.

public struct Point
{
    public double X { get; }
    public double Y { get; }
    
    public Point(double x, double y) => (X, Y) = (x, y);
}

интерфейсов,Interfaces

*Интерфейс* определяет контракт, который может быть реализован классами и структурами.An interface defines a contract that can be implemented by classes and structs. Интерфейс может содержать методы, свойства, события и индексаторы.An interface can contain methods, properties, events, and indexers. Интерфейс обычно не предоставляет реализацию элементов, которые в нем определены. Он лишь перечисляет элементы, которые должны быть определены в классах или структурах, реализующих этот интерфейс.An interface typically doesn't provide implementations of the members it defines—it merely specifies the members that must be supplied by classes or structs that implement the interface.

Интерфейсы могут применять *множественное наследование*.Interfaces may employ multiple inheritance. В следующем примере интерфейс IComboBox наследует одновременно от ITextBox и IListBox.In the following example, the interface IComboBox inherits from both ITextBox and IListBox.

interface IControl
{
    void Paint();
}

interface ITextBox : IControl
{
    void SetText(string text);
}

interface IListBox : IControl
{
    void SetItems(string[] items);
}

interface IComboBox : ITextBox, IListBox { }

Классы и структуры могут реализовывать несколько интерфейсов.Classes and structs can implement multiple interfaces. В следующем примере класс EditBox реализует одновременно IControl и IDataBound.In the following example, the class EditBox implements both IControl and IDataBound.

interface IDataBound
{
    void Bind(Binder b);
}

public class EditBox : IControl, IDataBound
{
    public void Paint() { }
    public void Bind(Binder b) { }
}

Если класс или структура реализует конкретный интерфейс, любой экземпляр этого класса или структуры можно неявно преобразовать в такой тип интерфейса.When a class or struct implements a particular interface, instances of that class or struct can be implicitly converted to that interface type. Например.For example

EditBox editBox = new EditBox();
IControl control = editBox;
IDataBound dataBound = editBox;

ПеречисленияEnums

Тип Enum определяет набор константных значений.An Enum type defines a set of constant values. В следующем объявлении enum определяются константы, соответствующие различным корнеплодам:The following enum declares constants that define different root vegetables:

public enum SomeRootVegetable
{
    HorseRadish,
    Radish,
    Turnip
}

Также можно определить enum, которое будет использоваться в виде сочетания флагов.You can also define an enum to be used in combination as flags. В следующем объявлении определяется набор флагов для четырех времен года.The following declaration declares a set of flags for the four seasons. Можно применить любое сочетание времен года, в том числе значение All, включающее все времена года:Any combination of the seasons may be applied, including an All value that includes all seasons:

[Flags]
public enum Seasons
{
    None = 0,
    Summer = 1,
    Autumn = 2,
    Winter = 4,
    Spring = 8,
    All = Summer | Autumn | Winter | Spring
}

В следующем примере показаны объявления для обоих указанных выше перечислений:The following example shows declarations of both the preceding enums:

var turnip = SomeRootVegetable.Turnip;

var spring = Seasons.Spring;
var startingOnEquinox = Seasons.Spring | Seasons.Autumn;
var theYear = Seasons.All;

Типы, допускающие значение NULLNullable types

Переменные любого типа могут быть объявлены как *не допускающие значение NULL* или *допускающие значение NULL*.Variables of any type may be declared as non-nullable or nullable. Переменная, допускающая значение NULL, может содержать дополнительное значение null, указывающее на отсутствие значения.A nullable variable can hold an additional null value, indicating no value. Типы значений, допускающие значение NULL (структуры или перечисления), представляются System.Nullable<T>.Nullable Value types (structs or enums) are represented by System.Nullable<T>. Ссылочные типы, не допускающие значение NULL и допускающие значение NULL, представляются базовым ссылочным типом.Non-nullable and Nullable Reference types are both represented by the underlying reference type. Различие представляется метаданными, которые считываются компилятором и некоторыми библиотеками.The distinction is represented by metadata read by the compiler and some libraries. Если ссылки, допускающие значение NULL, разыменовываются без предварительной проверки значения на null, компилятор выдает предупреждения.The compiler provides warnings when nullable references are dereferenced without first checking their value against null. Компилятор также выдает предупреждения, если ссылкам, не допускающим значение NULL, присваивается значение, которое может быть равно null.The compiler also provides warnings when non-nullable references are assigned a value that may be null. В следующем примере объявляется *переменная целочисленного типа, допускающая значение NULL*, и эта переменная инициализируется значением null.The following example declares a nullable int, initializing it to null. Затем ей присваивается значение 5.Then, it sets the value to 5. Затем те же действия выполняются для *строки, допускающей значение NULL*.It demonstrates the same concept with a nullable string. Дополнительные сведения см. в статьях Типы значений, допускающие значение NULL и Ссылочные типы, допускающие значение NULL.For more information, see nullable value types and nullable reference types.

int? optionalInt = default; 
optionalInt = 5;
string? optionalText = default;
optionalText = "Hello World.";

КортежиTuples

C# поддерживает _ кортежи*, которые предоставляют краткий синтаксис для группирования нескольких элементов данных в упрощенную структуру данных.C# supports _ tuples*, which provides concise syntax to group multiple data elements in a lightweight data structure. Чтобы создать экземпляр кортежа, необходимо объявить типы и имена элементов между ( и ), как показано в следующем примере:You instantiate a tuple by declaring the types and names of the members between ( and ), as shown in the following example:

(double Sum, int Count) t2 = (4.5, 3);
Console.WriteLine($"Sum of {t2.Count} elements is {t2.Sum}.");
// Output:
// Sum of 3 elements is 4.5.

Кортежи являются альтернативой для структуры данных с несколькими элементами. В них не используются стандартные блоки, описанные в следующей статье.Tuples provide an alternative for data structure with multiple members, without using the building blocks described in the next article.