Страницы

Поиск по вопросам

понедельник, 8 октября 2018 г.

Видимость private константы атрибутом

Пусть есть класс
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

Комментариев нет:

Отправить комментарий