Страницы

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

среда, 4 декабря 2019 г.

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

#c_sharp #language_lawyer #const #attribute


Пусть есть класс

class Class
{
}


и атрибут

class SomePropertyAttribute : Attribute
{
    public SomePropertyAttribute(string prop)
    {
    }
}


Почему компилятор не выдаёт ошибку, если применить атрибут к классу следующим образом

[SomeProperty(Weird)] //<-- Weird const use
class Class
{
    private const string Weird = nameof(Weird);
}


?

Ведь в данном случае приватная константа используется за пределами фигурных скобок,
определяющих класс. Тогда как документация (см. private) гласит:


  Ключевое слово private является модификатором доступа к члену.
  ...
  Доступ к закрытым членам можно получить только внутри тела
  класса или структуры, в которой они объявлены ...

    


Ответы

Ответ 1



Как ни странно, ваш пример не противоречит спецификации языка. Я не смог сам найти и правильно проинтерпретировать нужную цитату из стандарта, но мне помог аналогичный вопрос в гитхаб-репозитории компилятора. Как оказалось, разрешение имён (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.

Ответ 2



Атрибуты в C# добавляют метаданные на сборку. Если точнее - и на наш класс. В этой ситуации область видимости атрибута и константы совпадают на уровне компиляции. Поэтому ваш пример работает. TypeDef #2 (02000003) ------------------------------------------------------- TypDefName: XmlParsing.Class (02000003) Flags : [NotPublic] [AutoLayout] [Class] [AnsiClass] [BeforeFieldInit] (00100000) Extends : 01000011 [TypeRef] System.Object Field #1 (04000001) ------------------------------------------------------- Field Name: Weird (04000001) Flags : [Private] [Static] [Literal] [HasDefault] (00008051) DefltValue: (String) We CallCnvntn: [FIELD] Field type: String Signature : 06 0e Method #1 (06000002) ------------------------------------------------------- MethodName: .ctor (06000002) Flags : [Public] [HideBySig] [ReuseSlot] [SpecialName] [RTSpecialName] [.ctor] (00001886) RVA : 0x0000205a ImplFlags : [IL] [Managed] (00000000) CallCnvntn: [DEFAULT] hasThis ReturnType: Void No arguments. Signature : 20 00 01 CustomAttribute #1 (0c00000f) ------------------------------------------------------- CustomAttribute Type: 06000001 CustomAttributeName: XmlParsing.SomePropertyAttribute :: instance void .ctor(class System.String) Length: 10 Value : 01 00 05 57 65 69 72 64 00 00 > Weird < ctor args: ("Weird")

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

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