Пусть есть класс
class Class
{
}
и атрибут
class SomePropertyAttribute : Attribute
{
public SomePropertyAttribute(string prop)
{
}
}
Почему компилятор не выдаёт ошибку, если применить атрибут к классу следующим образом
[SomeProperty(Weird)] //<-- Weird const use
class Class
{
private const string Weird = nameof(Weird);
}
?
Ведь в данном случае приватная константа используется за пределами фигурных скобок, определяющих класс. Тогда как документация (см. private) гласит:
Ключевое слово private является модификатором доступа к члену.
...
Доступ к закрытым членам можно получить только внутри тела
класса или структуры, в которой они объявлены ...
Ответ
Как ни странно, ваш пример не противоречит спецификации языка.
Я не смог сам найти и правильно проинтерпретировать нужную цитату из стандарта, но мне помог аналогичный вопрос в гитхаб-репозитории компилятора. Как оказалось, разрешение имён (name resolution) для атрибутов класса проходит в контексте самого класса. Поэтому, кстати, вы можете ссылаться на константу просто как Weird, а не Class.Weird. «Нарушения» правил видимости тут не происходит, атрибут как бы находится внутри класса. Давайте найдём подтверждение этого в спецификации.
На этапе разрешения имён, Weird классифицируется как «простое имя» (simple name), и его привязка регулируется разделом 7.6.2 спецификации. Релевантная часть:
If K is zero and the simple_name appears within a block ... [не подходит — VladD]
If K is zero and the simple_name appears within the body of a generic method declaration ... [не подходит — VladD]
Otherwise, for each instance type T (The instance type), starting with the instance type of the immediately enclosing type declaration and continuing with the instance type of each enclosing class or struct declaration (if any):
Лирическо-бюрократическое отступление.
Подходит ли нам эта часть? Лежит ли атрибут вообще в какой либо декларации типа (immediately enclosing type declaration)? Кажется, что он лежит снаружи, но это не так. Согласно разделу 10.1, декларация класса является декларацией типа
A class_declaration is a type_declaration
и включает в себя объявление атрибутов:
A class_declaration consists of an optional set of attributes (Attributes), followed by...
Возвращаемся к теме. У нас T есть тип Class. В спецификации есть следующие подпункты:
If K is zero and the declaration of T includes a type parameter with name I ... [не подходит, у нас нет параметров-типов — VladD]
Otherwise, if a member lookup (Member lookup) of I in T with K type arguments produces a match
Эта часть подходит, т. к. Weird является константой-членом класса (в чём можно убедиться, пролистав раздел Member lookup).
Итак, в этом случае Weird разрешается как часть типа Class
Комментариев нет:
Отправить комментарий