Чи можна атрибути додавати динамічно в C #?


143

Чи можливо додати атрибути під час виконання або змінити значення атрибута під час виконання?

Відповіді:


67

Атрибути - це статичні метадані. Асамблеї, модулі, типи, члени, параметри та значення повернення - це не першокласні об'єкти в C # (наприклад, System.Typeклас є лише відображеним поданням типу). Ви можете отримати екземпляр атрибута для типу та змінити властивості, якщо вони доступні для запису, але це не вплине на атрибут, оскільки він застосовується до типу.


68

Це дійсно залежить від того, що саме ви намагаєтеся досягти.

Матеріали System.ComponentModel.TypeDescriptor можна використовувати для додавання атрибутів до типів, властивостей та примірників об'єктів, і це обмеження, що вам доведеться використовувати його і для отримання цих властивостей. Якщо ви пишете код, який споживає ці атрибути, і ви можете жити в межах цих обмежень, я б точно запропонував це.

Наскільки я знаю, управління PropertyGrid та поверхня дизайну візуальної студії - це єдині речі в BCL, які споживають речі TypeDescriptor. Насправді саме так вони роблять приблизно половину речей, які їм дійсно потрібно робити.


7
Насправді, більшість застосувань для зв’язку даних TypeDescriptor- не тільки PropertyGrid.
Марк Гравелл

1
Будь-яке вирішення щодо додавання атрибутів метаданих властивостей у проект Silverlight (де TypeDescriptorта TypeDescriptionProviderне реалізовано?
Shimmy Weitzhandler

1
Важливо зазначити, що TypeDescriptor.GetAttributes () не обробляє повторювані атрибути. Він вибирає лише останній тип атрибута. Знайдено [Attr(1), Attr(2), Attr(3)]лише екс Attr(3).
охмуса

11

Ви не можете. Одним із шляхів вирішення може бути генерування похідного класу під час виконання та додавання атрибуту, хоча це, ймовірно, є надмірним вбивством.


10

Ну, просто щоб бути іншим, я знайшов статтю, на яку посилаються, використовуючи Reflection.Emit.

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


10
Зауважте, що ви можете створювати атрибути під час виконання за допомогою класів Reflection.Emit, АЛЕ ви можете прив’язати їх до класів, які ви створили за допомогою пакету Emit, а не до існуючих.
Панос

яка непотрібна відповідь =)) Нас усіх цікавить існуючі тут класи, а не динамічні.
Безнадійне

@Hopeless, ви можете підкласи YourClassв YourRuntimeClassWithAttributes.
Мотес

@Motes не впевнений, що ви маєте на увазі, всі мої класи попередньо визначені, це означає, що всі базові класи (які мої класи успадковують) також повинні бути визначені / визначені заздалегідь. Я не можу придумати жодного способу, щоб він був пов'язаний з чимось динамічно створеним за допомогою Reflection.Emit.
Безнадійний

1
@Hopeless, якщо ви хочете динамічно додавати атрибути до існуючого класу YourClass, ви можете підкласифікувати його під час виконання та створити ідентичний клас із трохи іншим ім'ям, яке також має бажані динамічно створені атрибути, і поліморфізм дозволить перевірити тип коду, щоб все-таки ідентифікувати ваш базовий клас.
Мотес

4

Ні це не так.

Атрибути є метаданими та зберігаються у двійковій формі у складеній збірці (тому також можна використовувати в них лише прості типи).


3

Я не вірю в це. Навіть якщо я помиляюся, найкраще, на що можна сподіватися, - це додавання їх до цілого типу, а ніколи до екземпляра типу.


22
TypeDescriptor.AddAttributes (Object, Attribute []) додає атрибути рівня класу до екземпляра цільового компонента.
Пітер Вун

3

Якщо вам потрібно щось, щоб можна було динамічно додавати, c # атрибути - це не спосіб. Подивіться на зберігання даних у xml. Нещодавно я зробив проект, у якому я запустив w / атрибути, але врешті-решт перейшов до серіалізації w / xml.


1
можливо, це не прекрасний спосіб, але це те, як багато інших бібліотек вирішили використовувати, і щоб налаштувати поведінку цих бібліотек, ми маємо вимогу грати з відображенням =)) насправді тупик.
Безнадійне

3

Навіщо це потрібно? Атрибути дають додаткову інформацію для роздумів, але якщо ви зовні знаєте, які саме властивості вам потрібні, вони вам не потрібні.

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


1
Усунення котлопластини Чи не було б зручно, якби ви могли автоматично створювати атрибути класу на основі коду в класі? Я намагаюся розібратися з чимось подібним, щоб зменшити шаблони в об'єктах SQL CLR. Іншими мовами буде легко ... дивіться paulgraham.com/avg.html
Duncan Bayne

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);
                }
            }
        }

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.