Используйте отражение, чтобы установить значение поля в структуре, которая является частью массива структур.

На данный момент мой код успешно устанавливает значение полей/свойств/массивов объекта, используя отражение, учитывая путь к полю/свойству из корневого объекта.

e.g.

//MyObject.MySubProperty.MyProperty
SetValue('MySubProperty/MyProperty', 'new value', MyObject);

В приведенном выше примере для свойства «MyProperty» объекта «MyObject» будет установлено «новое значение».

Я не могу использовать отражение для установки значения поля в структуре, которая является частью массива структур, потому что структура является типом значения (внутри массива).

Вот несколько тестовых классов/структур...

public class MyClass {
        public MyStruct[] myStructArray = new MyStruct[] {
            new MyStruct() { myField = "change my value" } 
        };
        public MyStruct[] myOtherStructArray = new MyStruct[] {
            new MyStruct() { myOtherField = "change my value" }, 
            new MyStruct() { myOtherField = "change my other value" } 
        };
}

public struct MyStruct { public string myField; public string myOtherField; }

Ниже показано, как я успешно установил значение обычных свойств/полей и реквизитов/полей в списках...

public void SetValue(string pathToData, object newValue, object rootObject)
{
    object foundObject = rootObject;
    foreach (string element in pathToData.Split("/"))
    {
        foundObject = //If element is [Blah] then get the
                      //object at the specified list position
        //OR
        foundObject = //Else get the field/property
    }

    //Once found, set the value (this is the bit that doesn't work for
    //                           fields/properties in structs in arrays)
    FieldInf.SetValue(foundObject, newValue);
}

object myObject = new MyClass();
SetValue("/myStructArray/[0]/myField", "my new value", myObject);
SetValue("/myOtherStructArray/[1]/myOtherField", "my new value", myObject);

После этого я хочу, чтобы myObject.myStructArray[0].myField = ''мое новое значение" и myObject.myOtherStructArray[1].myOtherField = ''мое новое значение"

Все, что мне нужно, это замена 'FieldInf.SetValue(foundObject, newValue);' линия

заранее спасибо


person Mark    schedule 20.03.2009    source источник
comment


Ответы (4)


Получите FieldInfo для объекта массива (а не для конкретного элемента).

Если это массив, приведите его к System.Array и используйте Array.SetValue, чтобы установить значение объекта.

person Reed Copsey    schedule 21.03.2009
comment
Спасибо за ваш ответ, я не думаю, что это сработает, потому что структура выглядит следующим образом... MyObject.myStructArray[0].myField Итак, используя ваш метод Array.SetValue - person Mark; 21.03.2009
comment
... хотел бы передать новую структуру, я пытаюсь установить значение поля в структуре, которая находится в массиве - person Mark; 21.03.2009
comment
да. Всякий раз, когда у вас есть массив структур, это лучший подход. Вы можете скопировать его в новую локальную структуру и перезаписать только этот элемент, а затем передать его обратно. - person Reed Copsey; 21.03.2009
comment
Однако, как правило, структуры должны быть неизменяемыми, поэтому, как правило, следует избегать структур, в которых можно изменить один элемент. В руководстве по проектированию подробно объясняется, почему... - person Reed Copsey; 21.03.2009
comment
Хорошо спасибо. Похоже, я готовлюсь к ситуациям, которые никогда не произойдут на занятиях. PS Где эти рекомендации по дизайну, о которых вы говорите? - person Mark; 21.03.2009
comment
Часть рекомендаций по проектированию для платформ .net доступна в MSDN. Однако есть книга, написанная двумя людьми из MS, в которой подробно объясняются все рекомендации. Я очень рекомендую. - person Reed Copsey; 22.03.2009
comment
comment
Привет, я получил книгу через работу. Это очень тщательно, и в него приятно погрузиться для быстрого исправления информации во время работы. Какие еще хорошие книги по .NET вы могли бы порекомендовать? - person Mark; 30.03.2009

Из-за бокса/распаковки следующее должно делать именно то, что вы ищете, для любого члена структуры:

var property = this.GetType().GetProperty(myPropertyName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
ValueType vthis = this;
property.SetValue(vthis, myValue, null); // myValue is the value/object to be assigned to the property.
this = (UnderlyingsList)vthis;
person Erwin Mayer    schedule 17.06.2011

Если бы мне пришлось угадывать, ошибка находится в части кода, который вы пропустили, в частности, я бы подозревал, что:

    foundObject = //If element is [Blah] then get the
                  //object at the specified list position

является (непреднамеренной) установкой foundObject на копию объекта в указанной позиции списка.

person MarkusQ    schedule 20.03.2009

Продолжение моего вопроса...

Единственное решение, которое я нашел для аналогичной проблемы, у меня была установка поля/свойства в структуре, которая является полем, чтобы использовать...

//GrandParentObject is myObject
//GrandParentType is typeof(MyClass)
//FieldIWantedToSet is the field info of myStruct.FieldIWantedToSet
FieldInfo oFieldValueTypeInfo = GrandParentType.GetField("myStruct");
TypedReference typedRefToValueType = TypedReference.MakeTypedReference(GrandParentObject, new FieldInfo[] { oFieldValueTypeInfo });
FieldIWantedToSet.SetValueDirect(typedRefToValueType, "my new value"); 

Проблема в том, как я могу использовать SetValueDirect для массива/списка структур, я предполагаю, что мой старый метод выше не будет работать, когда структуры находятся в массиве, потому что я не могу получить FieldInfo для структуры (потому что она в массиве)?

person Mark    schedule 21.03.2009