Могут ли атрибуты быть добавлены динамически в C #?

143

Можно ли добавить атрибуты во время выполнения или изменить значение атрибута во время выполнения?

Джон Тернер
источник

Ответы:

67

Атрибуты являются статическими метаданными. Сборки, модули, типы, члены, параметры и возвращаемые значения не являются первоклассными объектами в C # (например, System.Typeкласс является просто отраженным представлением типа). Вы можете получить экземпляр атрибута для типа и изменить свойства, если они доступны для записи, но это не повлияет на атрибут, поскольку он применяется к типу.

Марк Сидаде
источник
68

Это действительно зависит от того, что именно вы пытаетесь достичь.

Компонент System.ComponentModel.TypeDescriptor можно использовать для добавления атрибутов к типам, свойствам и экземплярам объектов, и он имеет ограничение, которое необходимо использовать для извлечения этих свойств. Если вы пишете код, который использует эти атрибуты, и вы можете жить в рамках этих ограничений, то я определенно рекомендую это.

Насколько я знаю, элемент управления PropertyGrid и поверхность визуального дизайна студии - единственные вещи в BCL, которые потребляют материал TypeDescriptor. Фактически, именно так они делают примерно половину того, что им действительно нужно делать.

Алекс Лиман
источник
7
На самом деле, большинство привязок данных использует TypeDescriptor- не только PropertyGrid.
Марк Гравелл
1
Любой обходной путь для добавления атрибутов свойств-метаданных в проект Silverlight (где TypeDescriptorи TypeDescriptionProviderне реализовано?
Шимми Вейцхандлер
1
Важно отметить, что TypeDescriptor.GetAttributes () не обрабатывает дублирующиеся атрибуты. Он выбирает только последний тип атрибута. Экс [Attr(1), Attr(2), Attr(3)]только Attr(3)найден.
ohmusama
11

Ты не можешь Одним из обходных путей может быть создание производного класса во время выполнения и добавление атрибута, хотя это, вероятно, немного излишне.

петр к.
источник
10

Ну, просто чтобы быть другим, я нашел статью, которая ссылается на Reflection.Emit, чтобы сделать это.

Вот ссылка: http://www.codeproject.com/KB/cs/dotnetattributes.aspx , вы также захотите взглянуть на некоторые комментарии в нижней части статьи, потому что обсуждаются возможные подходы.

ториальную
источник
10
Обратите внимание, что вы можете создавать атрибуты во время выполнения с классами Reflection.Emit, НО вы можете связать их с классами, которые вы создали с помощью пакета Emit, а не с существующими.
Панос
какой бесполезный ответ =)) мы все заботимся о существующих классах, а не о динамических.
Безнадежно
@ Безнадежно, вы можете подкласс YourClassв YourRuntimeClassWithAttributes.
Motes
@Motes не уверен, что вы имеете в виду, все мои классы определены заранее, это означает, что все базовые классы (которые наследуют мои классы) также должны быть определены заранее. Я не могу придумать, каким образом это может быть связано с чем-то динамически созданным с помощью Reflection.Emit.
Безнадежный
1
@ Безнадежно, если вы хотите динамически добавлять атрибуты в существующий класс YourClass, вы можете создать его подкласс во время выполнения и сгенерировать идентичный класс с немного другим именем, который также имеет нужные динамически созданные атрибуты, и полиморфизм позволит коду проверки типа по-прежнему идентифицировать ваш базовый класс.
Motes
4

Нет, это не так.

Атрибуты являются метаданными и хранятся в двоичной форме в скомпилированной сборке (поэтому вы можете использовать в них только простые типы).

Томас Данекер
источник
3

Я не верю в это. Даже если я ошибаюсь, лучшее, на что вы можете надеяться, это добавить их ко всему типу, а не к экземпляру типа.

Джоэл Коухорн
источник
22
TypeDescriptor.AddAttributes (Object, Attribute []) добавляет атрибуты уровня класса к экземпляру целевого компонента.
Питер Воне
3

Если вам нужно что-то, чтобы иметь возможность динамически добавлять атрибуты c #, это не так. Посмотрите на хранение данных в XML. Недавно я сделал проект, который я начал с атрибутов, но в итоге перешел на сериализацию с xml.

Даррен Копп
источник
1
может быть, это не очень красивый способ, но многие другие библиотеки предпочитают его использовать, и для настройки поведения этих библиотек у нас есть требование поиграть с отражением =)) действительно тупик.
Безнадежный
3

Зачем тебе это? Атрибуты дают дополнительную информацию для размышления, но если вы извне знаете, какие свойства вам нужны, они вам не нужны.

Вы можете относительно легко хранить метаданные внешне в базе данных или файле ресурсов.

Кит
источник
1
Ликвидация котельной. Разве не было бы удобно, если бы вы могли иметь класс, автоматически генерирующий атрибуты на основе кода внутри класса? Я пытаюсь выяснить что-то вроде этого, чтобы уменьшить шаблон в объектах SQL CLR. Было бы легко на других языках ... см. Paulgraham.com/avg.html
Дункан Бэйн
1

Я очень старался с System.ComponentModel.TypeDescriptor без успеха. Это не значит, что это не может работать, но я хотел бы увидеть код для этого.

В противоположность, я хотел изменить некоторые значения атрибутов. Я сделал 2 функции, которые отлично работают для этой цели.

        // ************************************************************************
        public static void SetObjectPropertyDescription(this Type typeOfObject, string propertyName,  string description)
        {
            PropertyDescriptor pd = TypeDescriptor.GetProperties(typeOfObject)[propertyName];
            var att = pd.Attributes[typeof(DescriptionAttribute)] as DescriptionAttribute;
            if (att != null)
            {
                var fieldDescription = att.GetType().GetField("description", BindingFlags.NonPublic | BindingFlags.Instance);
                if (fieldDescription != null)
                {
                    fieldDescription.SetValue(att, description);
                }
            }
        }

        // ************************************************************************
        public static void SetPropertyAttributReadOnly(this Type typeOfObject, string propertyName, bool isReadOnly)
        {
            PropertyDescriptor pd = TypeDescriptor.GetProperties(typeOfObject)[propertyName];
            var att = pd.Attributes[typeof(ReadOnlyAttribute)] as ReadOnlyAttribute;
            if (att != null)
            {
                var fieldDescription = att.GetType().GetField("isReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
                if (fieldDescription != null)
                {
                    fieldDescription.SetValue(att, isReadOnly);
                }
            }
        }
Эрик Оуэлл
источник