54
Глава.1 .Модель.выполнения.кода.в.среде.CLR
// Предупреждение: идентификаторы 'SomeLibrary.SomeLibraryType.abc()',
// отличающиеся только регистром символов, не являются
// CLS-совместимыми
public void abc() { }
// Предупреждения нет: закрытый метод
private UInt32 ABC() { return 0; }
}
}
В этом коде атрибут
[assembly:CLSCompliant(true)]
применяется к сборке.
Этот атрибут приказывает компилятору следить за тем, чтобы тип с открытым
уровнем доступа не содержал конструкций, препятствующих
его использованию
в другом языке программирования. При компиляции этого кода компилятор C#
выдает два предупреждения. Первое выдается из-за того, что метод
Abc
возвращает
целое без знака; некоторые языки программирования не умеют работать с беззна-
ковыми целыми числами. Второе предупреждение выдается из-за того, что тип
содержит два открытых метода, различающихся только регистром и типом воз-
вращаемого значения:
Abc
и
abc
. В Visual Basic и некоторых других языках вызов
обоих методов невозможен.
Если
удалить ключевое слово
public
перед
sealed class
SomeLibraryType
и перекомпилировать код, оба предупреждения пропадают. Дело в том, что тип
SomeLibraryType
по умолчанию рассматривается как
internal
, а следовательно,
становится недоступным за пределами сборки. Полный список правил CLS при-
веден в разделе «Cross-Language Interoperability» документации .NET Framework
SDK (
http://msdn microsoft com/en-us/library/730f1wy3 aspx
).
Позвольте мне изложить правила CLS в предельно упрощенном виде. В
CLR
каждый член типа является либо полем (данные), либо методом (поведение). Это
означает, что каждый язык программирования должен уметь обращаться к полям
и вызывать методы. Некоторые поля и некоторые методы используются специ-
альным образом. Для упрощения программирования языки обычно предостав-
ляют дополнительные абстракции, упрощающие реализацию этих стандартных
паттернов — перечисления, массивы,
свойства, индексаторы, делегаты, события,
конструкторы, финализаторы, перегрузки операторов, операторы преобразования
и т. д. Когда компилятор встречает эти абстракции в исходном коде, он должен пре-
образовать их
в поля и методы, чтобы сделать их доступными для CLR и любых
других языков программирования.
Следующее определение типа содержит конструктор, финализатор, перегру-
женные операторы, свойство, индексатор и событие. Учтите,
что приведенный
код написан всего лишь для того, чтобы он компилировался, и не демонстрирует
правильного способа реализации типа.
using System;
internal sealed class Test {
55
CLS
// Конструктор
public Test() {}
// Финализатор
~Test() {}
// Перегрузка оператора
public static Boolean operator == (Test t1, Test t2) {
return true;
}
public static Boolean operator != (Test t1, Test t2) {
return false;
}
// Перегрузка оператора
public static Test operator + (Test t1, Test t2) { return null; }
// Свойство
public String AProperty {
get { return null; }
set { }
}
// Индексатор
public String this[Int32 x] {
get { return null; }
set { }
}
// Событие
public event EventHandler AnEvent;
}
Результатом компиляции этого кода является тип, содержащий набор полей
и методов. В
этом можно легко убедиться, просмотрев полученный управляемый
модуль в программе IL Disassembler (
ILDasm exe
), входящей в пакет .NET Framework
SDK (рис. 1.7).
В табл. 1.4 продемонстрировано соответствие между конструкциями языка про-
граммирования и эквивалентными полями/методами CLR.
Дополнительные узлы типа
Test
, не упомянутые в табл. 1.4 —
.class
,
.custom
,
AnEvent
,
AProperty
и
Item
, — содержат дополнительные метаданные типа. Они
не отображаются на поля или методы, а только предоставляют дополнительную
информацию о типе, которая может использоваться CLR, языками программи-
рования или инструментами. Например, программа может узнать, что тип
Test
поддерживает событие
AnEvent
, для работы с которым используются два метода
(
add_AnEvent
и
remove_AnEvent
).