Почему члены Атрибута должны быть публичными? - PullRequest
0 голосов
/ 05 июля 2018

Задача

Попытка использовать атрибут

internal class FooAttribute : Attribute
{
    internal string Bar { get; set; }
}

как это

[Foo(Bar = "hello world")]
public class MyOtherClass { }

(в той же сборке) дает

ошибка CS0617: 'Bar' не является допустимым аргументом именованного атрибута. Аргументы именованных атрибутов должны быть полями, которые не являются только для чтения, являются статическими или постоянными, или являются свойствами чтения-записи, которые являются открытыми и не являются статическими.

Тем не менее, я могу прекрасно получить доступ Bar из "в коде" , например,

FooAttribute attribute = new FooAttribute { Bar = "hello world" };

Решение

Однако, если я изменю атрибут на

internal class FooAttribute : Attribute
{
    public string Bar { get; set; }
    ^^^^^^
}

Я могу использовать его по назначению. Обратите внимание, что мне нужно было отметить только свойство public, но не сам атрибут. Это «исправило» проблему, несмотря на то, что эффективно не изменило видимость Bar.


Почему атрибуты «особые» в этом случае - почему компилятор требует, чтобы их поля были открытыми?

В документации об ошибке не упоминается , почему они также должны быть открытыми.

1 Ответ

0 голосов
/ 05 июля 2018

Почему атрибуты "специальные" в этом случае

Вы определяете не ту часть как особенную. Особенность атрибутов заключается в том, что существует синтаксис для комбинации создания и установки открытых свойств для объекта, связанного с полями, классами, методами и т. Д.

Другими словами, особенность атрибутов в том, что они являются атрибутами!

Действительно, это даже не атрибут, который является особенным; как вы сказали сами, вы можете создать экземпляр того же класса с инициализатором, как и любой другой. Это особый синтаксис атрибута.

Он должен разрешать возможность вызова открытого конструктора (или конструирование никогда не будет возможно), и он должен разрешать установку открытых свойств (или свойства никогда не будут установлены). Следует также отметить, что это предшествует введению синтаксиса инициализатора в C #, поэтому когда-то было возможно объединить конструирование и немедленную установку открытых свойств в одной синтаксической единице в случае атрибутов.

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

Итак, давайте просто рассмотрим [Foo(Bar = "hello world")] самостоятельно и подумаем, когда Bar должен быть настроен таким образом.

Причины, по которым это разрешено, когда Bar публично, должны быть довольно очевидными. Причины, по которым это не разрешается, когда Bar является приватным, также должны быть довольно очевидными. Когда его внутренний, есть два разумных выбора; не разрешать или разрешать, когда атрибут существует в данной сборке.

Таким образом, вопрос в том, насколько полезно иметь атрибут, который является открытым (если бы он сам был внутренним, мы могли бы достичь того же с общедоступными свойствами) и, следовательно, его можно использовать в других сборках, но который имеет внутренние свойства это может быть установлено только при использовании атрибутов из той же сборки. Если бы это было супер-полезно, то стоило бы дополнительной работы и сложности позволить это. Если это не было супер-полезно, то лучше, чтобы теория (спецификация) и практика (компилятор) не допустили этого.

Казалось бы, это не считалось сверхполезным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...