использование PropertyInfo для присвоения значения классу-оболочке с пользовательским индексатором

Мне нужно присвоить значение через PropertyInfo.

У меня возникают некоторые проблемы, когда типом свойства является мой собственный класс (оболочка словаря, предназначенная для содержания нескольких языковых версий одного и того же текста).

Это выглядит так:

    public class MultilingualString
    {               
        Dictionary<string, string> Versions;
        public string this[string languageCode]
        {
            get
            {
                if (Versions.Keys.Contains(languageCode))
                {
                    return Versions[languageCode];
                }
                return null;
            }
            set
            {
                if (Versions.Keys.Contains(languageCode))
                {
                    Versions[languageCode] = value;
                }
                else
                {
                    Versions.Add(languageCode, value);
                }
            }
            // [blah blah other stuff...]    
        }

Так; теперь у меня есть этот объект PropertyInfo и строковое значение, которое я хотел бы присвоить коду языка по умолчанию.

certainPropertyInfo.SetValue(
   instance, // an instance of some class exposing a MultilingualString type property 
   someString,
   new[] { "eng" }); // some default language code

Это вызывает исключение.

Я предполагаю, что последний аргумент SetValue должен быть индексом коллекции, и он не работает с пользовательским индексатором.

Фактически то, что я пытаюсь сделать, очевидно:

   instance.msProperty["eng"] = someString;

Но мне дается только имя msProperty, поэтому я использую отражение.

До сих пор я думал о реализации неявного оператора (в классе MultilingualString), позволяющего преобразовывать строковые значения в MultilingualString... но я вижу некоторые проблемы с этим подходом, например. этот статический оператор вряд ли сможет «узнать», что такое код языка по умолчанию.

Могу ли я достичь своей цели с помощью рефлексии?


person Konrad Morawski    schedule 12.07.2011    source источник
comment
у вас есть объект propertyinfo? И если да, то как вы получили объект? Вы уверены, что у вас есть правильный?   -  person Tomas Jansson    schedule 12.07.2011
comment
Кроме того, зачем вам нужно использовать отражение?   -  person Tomas Jansson    schedule 12.07.2011
comment
Я знаю тип объекта, и я динамически вызываю его (используя Activator) и заполняю его данными из DataTable. Предполагается, что пользователи приложения, которое я разрабатываю, сопоставляют столбцы DataTable с различными свойствами моих бизнес-классов.   -  person Konrad Morawski    schedule 12.07.2011


Ответы (1)


Индексатор является собственным свойством. Вам нужно получить свойство индексатора экземпляра в этом определенном вашем свойстве:

var multilingualString = certainPropertyInfo.GetValue(instance, null);
multilingualString.GetType().GetProperty("Item").SetValue(multilingualString,
                                                          someString,
                                                          new object[]{ "eng" });

Item — это имя по умолчанию для свойства индексатора.

Если вы используете .NET 4.0, вы можете использовать новый тип dynamic:

dynamic multilingualString = certainPropertyInfo.GetValue(instance, null);
multilingualString["eng"] = someString;
person Daniel Hilgarth    schedule 12.07.2011
comment
как ваше решение .NET 4.0... Никогда не думал об этом раньше. - person Tomas Jansson; 12.07.2011
comment
Но действительно ли вам нужно сначала использовать GetValue? Ты не можешь просто запустить dynamic multiStr = instance; multiStr["eng"] = someString; - person Tomas Jansson; 12.07.2011
comment
GetValue принимает как минимум два аргумента, второй из которых является необязательным значением индекса, и в любом случае возвращает null. Я использую .NET 3.5, поэтому не могу использовать динамический. - person Konrad Morawski; 12.07.2011
comment
@Tomas: Нет, вы не можете этого сделать, потому что экземпляр НЕ относится к типу MultilingualString, а к типу, содержащему свойство типа MultilingualString. Что бы вы могли сделать, если бы знали, что имя этого свойства будет следующим: dynamic multiStr = instance.TheKnownPropertyName; multiStr["eng"] = someString; - person Daniel Hilgarth; 12.07.2011
comment
это может быть так, но зачем ему вообще нужно делать GetValue при использовании dynamic. Если у него есть переменная экземпляра, он сможет установить ее сразу же, верно? - person Tomas Jansson; 12.07.2011
comment
ах... понятно... пропустил эту часть. - person Tomas Jansson; 12.07.2011
comment
ОК, я понял, почему GetValue все же возвращает null. Я забыл, что свойство не инициализировалось автоматически (не в конструкторе), и я забыл об этом позаботиться; дурак я. После исправления ваше решение работает отлично - спасибо! - person Konrad Morawski; 12.07.2011