Система общих типов CTS
Система общих типов CTS определяет способ объявления, использования и управления типами в среде CLR, а также является важной составной частью поддержки межъязыковой интеграции в среде выполнения. Система общих типов выполняет следующие функции.
Формирует инфраструктуру, которая позволяет обеспечивать межъязыковую интеграцию, безопасность типов и высокопроизводительное выполнение кода.
Предоставляет объектно-ориентированную модель, поддерживающую полную реализацию многих языков программирования.
Определяет правила, которых необходимо придерживаться в языке. Эти правила помогают обеспечить взаимодействие объектов, написанных на разных языках.
Предоставляет библиотеку, которая содержит типы-примитивы (например, Boolean, Byte, Char, Int32 и UInt64), используемые в разработке приложений.
Типы в .NET
Все типы на платформе .NET делятся на типы значений и ссылочные типы.
Типы значений — это типы данных, объекты которых представлены фактическим значением объекта. Если экземпляр типа значения присваивается переменной, то эта переменная получает новую копию значения.
Ссылочные типы — это типы данных, объекты которых представлены ссылкой (аналогичной указателю) на фактическое значение объекта. Если экземпляр ссылочного типа присваивается переменной, то эта переменная будет ссылаться (указывать) на исходное значение. Копирования при этом не происходит.
Система общих типов CTS на платформе .NET поддерживает следующие пять категорий типов:
Классы
Класс — это ссылочный тип, который может быть прямым производным от другого класса и является неявным производным от типа System.Object. В классе определяются операции, которые объект (являющийся экземпляром класса) может выполнять (методы, события или свойства), и данные, которые объект содержит (поля). Обычно класс включает и определение, и реализацию (в отличие, например, от интерфейса, который содержит только определение без реализации), однако один или несколько членов класса могут не иметь реализации.
В приведенной ниже таблице описываются некоторые характеристики, которыми может обладать класс. Каждый язык, поддерживающий среду выполнения, позволяет указать на наличие у класса или члена класса одной или нескольких из этих характеристик. Вместе с тем отдельные языки программирования, ориентированные на платформу .NET, могут не поддерживать некоторые из этих характеристик.
Characteristic | Description |
---|---|
sealed | Указывает, что наследование от данного класса не допускается. |
implements | Показывает, что в классе используется один или несколько интерфейсов за счет предоставления реализаций их членов. |
abstract | Указывает, что создавать экземпляры этого класса нельзя. Чтобы его использовать, необходимо создать из данного класса производный класс. |
inherits | Показывает, что экземпляры класса можно использовать везде, где задан базовый класс. Производный класс, который наследует от базового, может использовать реализацию любых открытых членов, предоставляемых базовым классом, либо переопределить реализацию этих открытых членов собственной их реализацией. |
exported или not exported | Показывает, виден ли класс за пределами сборки, в которой он определен. Эта характеристика применима только к классам верхнего уровня, но не к вложенным классам. |
Примечание.
Класс может также быть вложен в родительский класс или родительскую структуру. Вложенные классы также имеют характеристики членов. Дополнительные сведения см. в разделе Вложенные типы.
Члены классов, не имеющие реализации, являются абстрактными. Класс, содержащий несколько абстрактных членов, сам является абстрактным. Новые экземпляры этого класса создать нельзя. Некоторые языки, ориентированные на среду выполнения, позволяют пометить класс как абстрактный даже в том случае, если он не содержит ни одного абстрактного члена. Абстрактный класс можно использовать, когда требуется инкапсулировать базовый набор функциональных возможностей, которые производные классы могут наследовать или переопределять. Классы, не являющиеся абстрактными, называются конкретными классами.
Класс может реализовывать любое число интерфейсов, однако он может наследовать только от одного базового класса в дополнение к System.Object, от которого неявно наследуют все классы. Любой класс должен иметь по крайней мере один конструктор, который инициализирует новые экземпляры класса. Если конструктор не определен явно, большинство компиляторов автоматически предоставят заданный конструктор без параметров.
Структуры
Структура — это тип значения, неявно производный от типа System.ValueType, который, в свою очередь, является производным от типа System.Object. Структуры полезны для представления значений с небольшими требованиями к памяти и для передачи параметров по значению в методы со строгой типизацией параметров. В .NET все типы-примитивы (Boolean, Byte, Char, DateTime, Decimal, Double, Int16, Int32, Int64, SByte, Single, UInt16, UInt32 и UInt64) определяются как структуры.
Как и в классах, в структурах определяются и данные (поля структуры), и операции, которые можно выполнять над этими данными (методы структуры). Это означает, что применительно к структурам можно вызывать методы, в том числе виртуальные методы, определенные в классах System.Object и System.ValueType, а также любые методы, определенные в самом типе значения. Другими словами, структуры могут иметь поля, свойства и события, а также статические и нестатические методы. Можно создавать экземпляры структур, передавать их в качестве параметров, хранить их в качестве локальных переменных либо в поле другого типа значения или ссылочного типа. Структуры также могут реализовывать интерфейсы.
Кроме того, типы значений отличаются от классов в ряде других вопросов. Во-первых, хотя они неявно наследуют от System.ValueType, они не могут напрямую наследовать ни от какого типа. Аналогичным образом, все типы значений являются запечатанными. Это значит, что наследование от них не допускается. Им также не требуются конструкторы.
Для каждого типа значения среда CLR предоставляет соответствующий упакованный тип — класс, имеющий то же состояние и поведение, что и тип значения. Экземпляр типа значения упаковывается при передаче в метод, принимающий параметр типа System.Object. Распаковка (преобразование из экземпляра класса обратно в экземпляр типа значения) производится при возврате управления после вызова метода, принимающего тип значения в качестве параметра по ссылке. В некоторых языках необходимо применение специального синтаксиса, когда требуется упакованный тип; в других упакованный тип используется автоматически, когда он нужен. При определении типа значений определяется и упакованный, и неупакованный тип.
Перечисления
Перечисление — это тип значения, который напрямую наследует от System.Enum и предоставляет альтернативные имена для значений базового типа-примитива. Тип перечисления имеет имя, базовый тип, который должен быть одним из встроенных целочисленных знаковых или беззнаковых типов (например, Byte, Int32 или UInt64), а также набор полей. Поля являются статическими полями литералов, каждое из которых представляет константу. Одно значение можно присвоить нескольким полям. В этом случае необходимо пометить одно из значений как первичное значение перечисления для отражения и преобразования строк.
Значение базового типа можно присвоить перечислению и наоборот (среда выполнения не требует приведения типов). Можно создавать экземпляры перечислений и вызвать методы System.Enum, а также любые методы, определенные в базовом типе перечисления. При этом в некоторых языках передача перечисления в виде параметра может не допускаться, если требуется передать экземпляр базового типа (или наоборот).
К перечислениям применяются следующие дополнительные ограничения.
В них нельзя определять собственные методы.
В них нельзя реализовывать интерфейсы.
В них нельзя определять свойства и события.
Они не могут быть универсальными, если только они становятся таковыми за счет вложения внутрь универсального типа. То есть перечисления не могут иметь свои собственные параметры типов.
Примечание.
Вложенные типы (в том числе перечисления), созданные в Visual Basic, C# и C++, содержат параметры всех включающих их универсальных типов и, таким образом, являются универсальными, даже если они не имеют своих собственных параметров типов. Дополнительные сведения см. в подразделе "Вложенные типы" раздела справки Type.MakeGenericType.
Атрибут FlagsAttribute обозначает специальный вид перечисления, называемый битовым полем. Среда выполнения (в отличие от языка программирования) не различает обычные перечисления и битовые поля. Если это отличие обнаружено, для создания неименованных значений в битовых полях можно использовать битовые операторы (в перечислениях их использовать нельзя). Перечисления обычно используются для списков уникальных элементов, например дней недели, названий стран или областей и т. д. Битовые поля обычно используются для списков количеств и качеств, которые могут возникать в таких комбинациях, как Red And Big And Fast
.
В следующем примере показан способ использования битовых полей и обычных перечислений.
using System;
using System.Collections.Generic;
// A traditional enumeration of some root vegetables.
public enum SomeRootVegetables
{
HorseRadish,
Radish,
Turnip
}
// A bit field or flag enumeration of harvesting seasons.
[Flags]
public enum Seasons
{
None = 0,
Summer = 1,
Autumn = 2,
Winter = 4,
Spring = 8,
All = Summer | Autumn | Winter | Spring
}
public class Example
{
public static void Main()
{
// Hash table of when vegetables are available.
Dictionary<SomeRootVegetables, Seasons> AvailableIn = new Dictionary<SomeRootVegetables, Seasons>();
AvailableIn[SomeRootVegetables.HorseRadish] = Seasons.All;
AvailableIn[SomeRootVegetables.Radish] = Seasons.Spring;
AvailableIn[SomeRootVegetables.Turnip] = Seasons.Spring |
Seasons.Autumn;
// Array of the seasons, using the enumeration.
Seasons[] theSeasons = new Seasons[] { Seasons.Summer, Seasons.Autumn,
Seasons.Winter, Seasons.Spring };
// Print information of what vegetables are available each season.
foreach (Seasons season in theSeasons)
{
Console.Write(String.Format(
"The following root vegetables are harvested in {0}:\n",
season.ToString("G")));
foreach (KeyValuePair<SomeRootVegetables, Seasons> item in AvailableIn)
{
// A bitwise comparison.
if (((Seasons)item.Value & season) > 0)
Console.Write(String.Format(" {0:G}\n",
(SomeRootVegetables)item.Key));
}
}
}
}
// The example displays the following output:
// The following root vegetables are harvested in Summer:
// HorseRadish
// The following root vegetables are harvested in Autumn:
// Turnip
// HorseRadish
// The following root vegetables are harvested in Winter:
// HorseRadish
// The following root vegetables are harvested in Spring:
// Turnip
// Radish
// HorseRadish
Imports System.Collections.Generic
' A traditional enumeration of some root vegetables.
Public Enum SomeRootVegetables
HorseRadish
Radish
Turnip
End Enum
' A bit field or flag enumeration of harvesting seasons.
<Flags()> Public Enum Seasons
None = 0
Summer = 1
Autumn = 2
Winter = 4
Spring = 8
All = Summer Or Autumn Or Winter Or Spring
End Enum
' Entry point.
Public Class Example
Public Shared Sub Main()
' Hash table of when vegetables are available.
Dim AvailableIn As New Dictionary(Of SomeRootVegetables, Seasons)()
AvailableIn(SomeRootVegetables.HorseRadish) = Seasons.All
AvailableIn(SomeRootVegetables.Radish) = Seasons.Spring
AvailableIn(SomeRootVegetables.Turnip) = Seasons.Spring Or _
Seasons.Autumn
' Array of the seasons, using the enumeration.
Dim theSeasons() As Seasons = {Seasons.Summer, Seasons.Autumn, _
Seasons.Winter, Seasons.Spring}
' Print information of what vegetables are available each season.
For Each season As Seasons In theSeasons
Console.WriteLine(String.Format( _
"The following root vegetables are harvested in {0}:", _
season.ToString("G")))
For Each item As KeyValuePair(Of SomeRootVegetables, Seasons) In AvailableIn
' A bitwise comparison.
If (CType(item.Value, Seasons) And season) > 0 Then
Console.WriteLine(" " + _
CType(item.Key, SomeRootVegetables).ToString("G"))
End If
Next
Next
End Sub
End Class
' The example displays the following output:
' The following root vegetables are harvested in Summer:
' HorseRadish
' The following root vegetables are harvested in Autumn:
' Turnip
' HorseRadish
' The following root vegetables are harvested in Winter:
' HorseRadish
' The following root vegetables are harvested in Spring:
' Turnip
' Radish
' HorseRadish
Интерфейсы
Интерфейс задает контракт, определяющий отношение типа "может" или "имеет". Интерфейсы часто используются для реализации различных функций, например для сравнения и сортировки (интерфейсы IComparable и IComparable<T>), проверки равенства (интерфейс IEquatable<T>) или перечисления элементов коллекции (интерфейсы IEnumerable и IEnumerable<T>). Интерфейсы могут иметь свойства, методы и события, являющиеся абстрактными членами. Это значит, что хотя в интерфейсе определяются члены и их сигнатуры, за определение функциональности всех членов интерфейса отвечает тип, реализующий данный интерфейс. Любой класс или структура, реализующие интерфейс, должны содержать определения абстрактных членов, объявленных в этом интерфейсе. Обязательным условием реализации интерфейса в классе или структуре также может быть реализация одного или нескольких других интерфейсов.
К интерфейсам применяются следующие ограничения.
- Интерфейс может быть объявлен с любой доступностью, однако, члены интерфейса всегда должны иметь доступность уровня public.
- В интерфейсах нельзя определять конструкторы.
- В интерфейсах нельзя определять поля.
- В интерфейсах можно определять только члены экземпляров. Статические члены определять в них нельзя.
Поскольку в нескольких интерфейсах могут быть объявлены члены с одной и той же сигнатурой, имеющие разные реализации, любой язык должен предоставлять правила сопоставления реализации с интерфейсом, для которого требуется данный член.
Делегаты
Делегаты — это ссылочные типы, аналогичные по назначению указателям на функции в языке C++. Они применяются в обработчиках событий и функциях обратного вызова в составе платформы .NET. В отличие от указателей функций, делегаты являются безопасными, проверяемыми и типобезопасными. Тип делегата может представлять любой метод экземпляра или статический метод, имеющий совместимую сигнатуру.
Если тип параметра делегата является более строгим, чем тип параметра метода, то параметр делегата совместим с соответствующим параметром метода, так как это гарантирует, что аргумент, переданный делегату, может быть безопасно передан методу.
Аналогичным образом, тип возвращаемого значения делегата совместим с типом возвращаемого значения метода, если тип возвращаемого значения метода является более строгим, чем тип возвращаемого значения делегата, так как это гарантирует, что возвращаемое значение метода может быть безопасно приведено к типу возвращаемого значения делегата.
Например, делегат с параметром типа IEnumerable и типом возвращаемого значения Object может представлять метод с параметром типа Object и типом возвращаемого значения IEnumerable. Дополнительные сведения и примеры с кодом см. в разделе Delegate.CreateDelegate(Type, Object, MethodInfo).
Делегат называют связанным с методом, который он представляет. Помимо привязки к методу, делегат может быть связан с отдельным объектом. Этот объект представляет первый параметр метода и передается методу при каждом вызове делегата. Если это метод экземпляра, то связанный объект передается как неявный параметр this
(Me
в Visual Basic); если метод является статическим, то объект передается как первый формальный параметр метода, и сигнатура делегата при этом должна соответствовать остальным параметрам. Дополнительные сведения и примеры с кодом см. в разделе System.Delegate.
Все делегаты наследуются от System.MulticastDelegate, который наследуется от System.Delegate. Языки C#, Visual Basic и C++ не допускают наследование от этих типов. Вместо этого они предоставляют ключевые слова для объявления делегатов.
Поскольку делегаты наследуются от MulticastDelegate, делегат имеет список вызова, представляющий собой список методов, которые представляет делегат и которые выполняются при вызове делегата. Все методы в списке получают аргументы, предоставляемые при вызове делегата.
Примечание.
Для делегата, имеющего более одного метода в списке вызовов, возвращаемое значение не определяется, даже если у делегата есть возвращаемый тип.
Зачастую, как, например, в случае с методами обратного вызова, делегат представляет только один метод, поэтому единственное действие, которое нужно выполнить, — это создание и вызов делегата.
Для делегатов, представляющих несколько методов, .NET предоставляет в классах делегатов методы Delegate и MulticastDelegate для поддержки таких операций, как добавление методов к списку вызовов делегата (метод Delegate.Combine), удаление метода (метод Delegate.Remove) и получение списка вызовов (метод Delegate.GetInvocationList).
Примечание.
Применение этих методов к делегатам обработчиков событий в C#, C++ и Visual Basic необязательно, так как эти языки предоставляют синтаксис для добавления и удаления обработчиков событий.
Определения типов
Определение типа включает следующее:
- все определенные в типе атрибуты;
- доступность (видимость) типа;
- имя типа;
- базовый тип данного типа;
- все интерфейсы, реализованные этим типом;
- определения каждого члена типа.
Атрибуты
Атрибуты предоставляют дополнительные пользовательские метаданные. Они чаще всего используются для хранения дополнительной информации о типе в его сборке либо для изменения поведения члена типа во время разработки или выполнения.
Сами атрибуты представляют собой классы, производные от System.Attribute. Любой язык, поддерживающий использование атрибутов, имеет собственный синтаксис для применения атрибутов к элементам языка. Атрибуты можно применять почти к любым элементам языка; конкретные элементы, к которым можно применять определенный атрибут, задаются атрибутом AttributeUsageAttribute, примененным к классу этого атрибута.
Доступность типов
Все типы имеют модификатор, который определяет их доступность из других типов. В следующей таблице описаны виды доступности типов, поддерживаемые в среде выполнения.
Специальные возможности | Description |
---|---|
public | Тип доступен во всех сборках. |
сборка | Тип доступен только в пределах своей сборки. |
Доступность вложенного типа зависит от домена доступности, который определяется объявленным уровнем доступности члена и доменом доступности непосредственно вмещающего его типа. Однако домен доступности вложенного типа не может выходить за границы домена доступности содержащего его типа.
Домен доступности вложенного члена M
, объявленного в типе T
в рамках программы P
, определяется следующим образом (при этом M
также может быть типом):
Если объявленный уровень доступности
M
—public
, то домен доступностиM
совпадает с доменом доступностиT
.Если объявленный уровень доступности
M
—protected internal
, то домен доступностиM
представляет собой пересечение домена доступностиT
с текстом программыP
и текстом программ любого типа, производного отT
и объявленного внеP
.Если объявленный уровень доступности
M
—protected
, то домен доступностиM
представляет собой пересечение домена доступностиT
с текстом программыT
и текстом программы любого типа, производного отT
.Если объявленный уровень доступности
M
—internal
, то домен доступностиM
представляет собой пересечение домена доступностиT
с текстом программыP
.Если объявленный уровень доступности
M
—private
, то домен доступностиM
совпадает с текстом программыT
.
Имена типов
Система общих типов накладывает на имена только два следующих ограничения.
- Все имена кодируются в виде строк, состоящих из символов Юникода (16-разрядная кодировка).
- Имена не могут иметь внедренное (16-разрядное) значение 0x0000.
Тем не менее в большинстве языков на имена типов налагаются дополнительные ограничения. Все сравнения выполняются на побайтовой основе, поэтому в них учитывается регистр, но они не зависят от языкового стандарта.
Несмотря на то, что тип может ссылаться на типы из других модулей и сборок, он должен полностью определяться в одном модуле платформы .NET. (Однако в зависимости от поддержки компилятора его можно разделить на несколько файлов исходного кода.) Имена типов должны быть уникальными только в пространстве имен. Для полной идентификации типа его имя должно квалифицироваться именем пространства имен, в котором содержится реализация этого типа.
Базовые типы и интерфейсы
Тип может наследовать значения и поведение другого типа. Система общих типов не разрешает наследование от нескольких базовых типов.
Тип может реализовывать любое число интерфейсов. Для этого он должен реализовать все виртуальные члены этого интерфейса. Виртуальный метод может быть реализован с помощью производного типа и может вызываться либо статически, либо динамически.
Члены типов
Среда выполнения позволяет определять члены типа, задающих поведение и состояние типа. К членам типа относятся:
Поля
Поле описывает и содержит часть состояния типа. Поля могут иметь любой тип, поддерживаемый средой выполнения. Поля чаще всего имеют уровень доступности private
или protected
, поэтому они доступны только изнутри самого класса или из производных от него классов. Если значение поля может быть изменено извне его типа, то для этого обычно используется метод доступа набора свойств. Открытые поля обычно доступны только для чтения и могут относиться к одному из двух типов:
- Константы, значение которых задается во время разработки. Они являются статическими членами класса, хотя и не определяются с помощью ключевого слова
static
(Shared
в Visual Basic). - Доступные только для чтения переменные, значения которых задаются в конструкторе класса.
В следующем примере демонстрируются эти два способа использования доступных только для чтения полей.
using System;
public class Constants
{
public const double Pi = 3.1416;
public readonly DateTime BirthDate;
public Constants(DateTime birthDate)
{
this.BirthDate = birthDate;
}
}
public class Example
{
public static void Main()
{
Constants con = new Constants(new DateTime(1974, 8, 18));
Console.Write(Constants.Pi + "\n");
Console.Write(con.BirthDate.ToString("d") + "\n");
}
}
// The example displays the following output if run on a system whose current
// culture is en-US:
// 3.1416
// 8/18/1974
Public Class Constants
Public Const Pi As Double = 3.1416
Public ReadOnly BirthDate As Date
Public Sub New(birthDate As Date)
Me.BirthDate = birthDate
End Sub
End Class
Public Module Example
Public Sub Main()
Dim con As New Constants(#8/18/1974#)
Console.WriteLine(Constants.Pi.ToString())
Console.WriteLine(con.BirthDate.ToString("d"))
End Sub
End Module
' The example displays the following output if run on a system whose current
' culture is en-US:
' 3.1416
' 8/18/1974
Свойства
Свойство задает определенное значение или состояние типа, а также определяет методы получения и установки значения свойства. Свойства могут быть простыми типами, коллекциями простых типов, пользовательскими типами или коллекциями пользовательских типов. Свойства часто используются, чтобы обеспечить независимость общего интерфейса типа от фактической реализации данного типа. Это позволяет представлять с помощью свойств значения, которые не хранятся непосредственно в классе (например, когда свойство возвращает вычисляемое значение), либо выполнять проверку перед присваиванием значений закрытым полям. В следующем примере демонстрируется второй вариант.
using System;
public class Person
{
private int m_Age;
public int Age
{
get { return m_Age; }
set {
if (value < 0 || value > 125)
{
throw new ArgumentOutOfRangeException("The value of the Age property must be between 0 and 125.");
}
else
{
m_Age = value;
}
}
}
}
Public Class Person
Private m_Age As Integer
Public Property Age As Integer
Get
Return m_Age
End Get
Set
If value < 0 Or value > 125 Then
Throw New ArgumentOutOfRangeException("The value of the Age property must be between 0 and 125.")
Else
m_Age = value
End If
End Set
End Property
End Class
Помимо включения самого свойства, общий промежуточный язык (CIL) для типа, содержащего доступное для чтения свойство, включает метод propertyname, а CIL для типа, содержащего записываемое свойство, включает get_
set_
метод propertyname.
Методы
Метод описывает операции, доступные в определенном типе. Сигнатура метода указывает допустимые типы всех его параметров и возвращаемого значения.
Хотя большинство методов определяют точное число параметров, необходимых для вызовов метода, некоторые методы поддерживают переменное число параметров. Конечный объявленный параметр этих методов помечается атрибутом ParamArrayAttribute. Компиляторы языка обычно предоставляют ключевое слово, такое как params
в C# и ParamArray
в Visual Basic, которое исключает необходимость явного использования ParamArrayAttribute.
Конструкторы
Конструктор — это специальный метод, который служит для создания новых экземпляров класса или структуры. Как и любой другой метод, конструктор может иметь параметры, однако у конструкторов отсутствует возвращаемое значение (они возвращают void
).
Если исходный код класса не содержит явного определения конструктора, то компилятор включает заданный конструктор без параметров. Однако если исходный код класса определяет только параметризованные конструкторы, компиляторы Visual Basic и C# не создают конструктор без параметров.
Если исходный код для структуры определяет конструкторы, они должны быть параметризованы; структура не может определять конструктор (без параметров), и компиляторы не создают конструкторы без параметров для структур и других типов значений. Все типы значений не имеют неявного конструктора без параметров. Этот конструктор реализован средой CLR и инициализирует все поля структуры, задавая для них значения по умолчанию.
События
Событие определяет происшествие, на которое можно реагировать, а также методы подписки, отказа от подписки или порождения события. События часто используются для оповещения других типов об изменениях состояния. Для получения дополнительной информации см. Events.
Вложенные типы
Вложенный тип — это тип, являющийся членом какого-либо другого типа. Вложенные типы должны быть тесно связаны со своим вмещающим типом и не должны использоваться в качестве типа общего назначения. Вложенные типы полезны, когда объявляющий тип использует и создает экземпляры вложенного типа и использование вложенного типа не открывается в публичных членах.
Особенности вложенных типов не всегда понятны некоторым разработчикам; эти типы не должны быть открыто видимыми, если существенной причины для подобной видимости не имеется. В хорошо спроектированной библиотеке разработчикам редко приходится использовать вложенные типы для создания экземпляров объектов или объявления переменных.
Характеристики членов типов
Система общих типов CTS допускает наличие у членов типов различных характеристик, однако некоторые характеристики могут не поддерживаться в отдельных языках программирования. В следующей таблице описаны характеристики членов.
Characteristic | Применение | Description |
---|---|---|
abstract | Методы, свойства и события | Тип не предоставляет реализацию метода. Типы, которые наследуют или реализуют абстрактный метод, должны предоставлять реализацию метода. Единственное исключение — когда производный тип является абстрактным. Все абстрактные методы являются виртуальными. |
private, family, assembly, family and assembly, family or assembly, public | Все | Определяют доступность члена. private Доступен только изнутри типа, к которому принадлежит член, или изнутри вложенного типа. семейство Доступен изнутри типа, к которому принадлежит член, а также из производных от него типов. сборка Доступен только в сборке, в которой определен тип. family and assembly Доступен только в типах с уровнем доступа family и assembly. family or assembly Доступен только в типах с уровнем доступа либо family, либо assembly. public Доступен в любом типе. |
final | Методы, свойства и события | Виртуальный метод нельзя переопределить в производном типе. |
initialize-only | Поля | Значение можно только инициализировать и невозможно установить после инициализации. |
экземпляр | Поля, методы, свойства и события | Если член не помечен как static (C# и C++), Shared (Visual Basic), virtual (C# и C++) или Overridable (Visual Basic), то он является членом экземпляра (ключевое слово instance не используется). Копий таких членов в памяти будет столько, сколько объектов их использует. |
литерал | Поля | Значение, присвоенное полю, является фиксированным значением встроенного типа значения и становится известным во время компиляции. Поля литералов иногда называются константами. |
newslot или override | Все | Определяет способ взаимодействия члена с унаследованными членами, имеющими ту же сигнатуру: newslot Скрывает унаследованные члены с той же сигнатурой. override Заменяет определение наследуемого виртуального метода. По умолчанию используется характеристика newslot. |
static | Поля, методы, свойства и события | Член принадлежит к типу, в котором он определен, а не к конкретному экземпляру типа. Член существует, даже если экземпляр типа не создан, и является общим для всех экземпляров типа. |
виртуальная | Методы, свойства и события | Метод может реализовываться с помощью производного типа и вызываться либо статически, либо динамически. Если используется динамический вызов, то вызываемая реализация метода определяется типом экземпляра, выполняющего вызов во время выполнения, а не типом, известным во время компиляции. Для статического вызова виртуального метода может потребоваться приведение переменной к типу, который использует нужную версию метода. |
Перегрузка
У каждого члена типа есть уникальная сигнатура. Сигнатуры методов содержат имя метода и список параметров (порядок и типы аргументов метода). В типе можно определить несколько методов с одним именем и разными сигнатурами. При этом метод будет называться перегруженным. Например, в System.Char метод IsDigit перегружен. Один метод принимает параметр Char. Другой метод принимает String и Int32.
Примечание.
Тип возвращаемого значения не считается частью сигнатуры метода. Это значит, что методы не могут быть перегружены, если они различаются только типом возвращаемого значения.
Наследование, переопределение и скрытие членов
Производный тип наследует все члены своего базового типа. Эти члены будут определены для производного типа и доступны в нем. Поведение или характеристики наследуемых членов можно изменить двумя способами.
В производном типе можно скрыть наследуемый член, определив новый член с такой же сигнатурой. Это может понадобиться для того, чтобы сделать ранее открытый член закрытым или определить новое поведение для унаследованного метода, помеченного как
sealed
.Производный тип может переопределять наследуемый виртуальный метод. Переопределяющий метод предоставляет новое определение метода, который будет вызываться, на основании типа значения во время выполнения, а не типа переменной, известной во время компиляции. Метод может переопределить виртуальный метод только в том случае, если виртуальный метод не помечен как
sealed
, и при этом уровень доступности нового метода не ниже уровня доступности виртуального метода.