В C # Как изменить атрибут DefaultValue свойства в классе, который не наследуется?

1

Вот моя ситуация:

У меня есть сторонний компонентный элемент управления, который я успешно унаследовал, и теперь я делаю некоторую кумуляцию.

Часть этой настройки заключается в изменении значений DefaultValues некоторых свойств, которые у него есть.

Пока все прошло хорошо, но в этом элементе управления есть несколько классов "Sub", которые я хочу изменить и по умолчанию.

Под классами "Sub" я имею в виду: пусть говорят, что мой элемент управления называется SomeControl, поэтому он имеет свойства в нем, но он также имеет свойство, которое может расширяться, например: SomeControl.Rows, свойство.Rows возвращает RowCollection, у которого есть свой собственный свойства. Итак, это то, что я имею в виду под классом "Sub" (пожалуйста, поправьте меня, если у вас есть лучший термин для этого)

В любом случае, если я хочу изменить некоторые значения DefaultValues в классе RowCollection, мне тоже нужно наследовать его. Пропаганда заключается в том, что RowCollection Ctor является внутренним, поэтому я не могу наследовать этот класс.

Итак, есть ли другой способ изменить атрибут DefaultValue для свойства в классе, который я не могу наследовать?

Может быть, через отражение?

Мне нужно изменить его для экземпляра (объекта), который у меня есть - один экземпляр, а не для класса вообще.. (поскольку после создания из него 1 объекта больше не создается..)

спасибо

  • 0
    Вероятно, вам следует говорить о вложенных объектах, а не о подклассах , поскольку это может ввести в заблуждение относительно подклассов в смысле дочерних классов. В любом случае, вы имеете в виду этот атрибут DefaultValue ? Можете ли вы объяснить, почему вам нужно заменить его, а не присваивать значения свойств не по умолчанию вашему одному измененному экземпляру?
  • 0
    1) ОК, вложенные объекты. Да, я знал, что термин «подклассы» может сбивать с толку, поэтому я поставил часть «подклассы» в скобках. (Старый термин «подкласс» был заменен термином «наследование»)
Показать ещё 3 комментария
Теги:
winforms

1 ответ

1
Лучший ответ

Реферат: Я не думаю, что это можно сделать с помощью рефлексии, но вот как я это сделаю:

Сначала получите имущество, которое вы хотите:

var defValAttr = typeof (SomeControl.RowCollection)
     .GetProperty("yourProperty")
     .GetCustomAttributes(typeof(DefaultValueAttribute), false)
     .First()
     as DefaultValueAttribute;

DefaultValueAttribute имеет свойство.Value, которое является readonly. Чтобы изменить его, вам нужно снова отразить изменение частного поля.value:

var valueField= typeof (DefaultValueAttribute)
     .GetField("value", BindingFlags.NonPublic 
                      | BindingFlags.GetField 
                      | BindingFlags.Instance);

valueField.SetValue(defValAttr, yourNewDefaultValue);

Я сам не проверял это, но, насколько я знаю, это не сработает. Объекты, возвращаемые GetCustomAttributes, не являются фактическими атрибутами; вы можете получить значения реальных атрибутов таким образом, но вы не можете их изменить. (см. Могут ли атрибуты добавляться динамически в С#?)

Однако, даже если это будет работать, оно изменит значение DefaultValue для всех экземпляров SomeControl.Rows, независимо от того, находятся ли они в вашем настраиваемом контроле или в базовом элементе управления. Невозможно изменить только значение DefaultValue одного экземпляра, так как это значение сохраняется только один раз для каждого класса, а не один раз для каждого экземпляра. Было бы очень расточительно, если бы была копия каждого атрибута для каждого экземпляра объекта.

Поэтому в заключение я не думаю, что есть способ сделать это.

В качестве альтернативы вы можете декомпилировать стороннюю сборку и добавить свою собственную сборку с InternalsVisibleTo, чтобы вы могли получить доступ к внутреннему конструктору.


Добавление: Возможно, все еще есть способ сделать это, в зависимости от того, какой атрибут вы хотите изменить. Атрибуты, доступные через отражение, как я сказал, вероятно неизменны. Однако редактор визуальной студии и вся модель компонента WPF фактически используют TypeDescriptor для управления атрибутами поверх базовой системы атрибутов, встроенной в язык. Вы можете изменить атрибуты, используемые TypeProvider, и если код позже будет обращаться к атрибутам через TypeDescriptor, он может видеть измененные значения.

Далее не тестируется следующее:

var instanceOfRow = instanceOfYourControl.Rows;
var defValAttr = TypeDescriptor
     .GetProperties(instanceOfRow)["yourProperty"]
     .Attributes[typeof (DefaultValueAttribute)]
     as DefaultValueAttribute;

var valueField= typeof (DefaultValueAttribute)
     .GetField("value", BindingFlags.NonPublic 
                      | BindingFlags.GetField 
                      | BindingFlags.Instance);

valueField.SetValue(defValAttr, yourNewDefaultValue);
  • 0
    Спасибо Хьюго за этот ответ. Я пытаюсь код прямо сейчас, скоро сообщу ..
  • 0
    Хорошо, я проверил это сейчас. Он успешно изменяет значение только для экземпляра DefaultValueAttribute, который я получил, но не для экземпляра, который использует элемент управления. Точно так же, как вы сказали .. может быть, мы можем сделать трюк? Может быть, мы можем взять тот экземпляр, который мы успешно изменили, и затем каким-то образом заменить экземпляр элемента управления на этот отредактированный экземпляр ... Это возможно?
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню