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

271
31 августа 2017, 17:06

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

class Class
{
}

и атрибут

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

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

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

?

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

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

Answer 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.

Answer 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")
READ ALSO
Возможно ли перегрузить метод Console.WriteLine

Возможно ли перегрузить метод Console.WriteLine

Возможно ли перегрузить метод ConsoleWriteLine ?

241
Как получить данные из базы данных?

Как получить данные из базы данных?

У меня есть бд, которая выглядит таким образом:

266