简体   繁体   中英

SetValue of Indexed Property in C# using Reflection

I have a class which has an

ObservableCollection<int>

as a property, and I'm trying to change a value inside that property of an instance of that class. Here's the code I have and that's getting a TargetException:

object[] index = null;
var originalPropertyName = propertyName;
if (propertyName.Contains("[") && propertyName.Contains("]"))
{
    index = new object[1];
    index[0] = Convert.ToInt32(propertyName.Split('[')[1].Split(']')[0]);
    propertyName = propertyName.Split('[')[0];
}
PropertyInfo pi = item.GetType().GetProperty(propertyName);
PropertyInfo opi = item.GetType().GetProperty(originalPropertyName);
Type pType = index != null ? pi.PropertyType.GetGenericArguments()[0] : pi.PropertyType;
if (pi != null)
{
    object convertedValue = Convert.ChangeType(value, pType);
    if (index == null)
    {
        item.GetType().GetProperty(propertyName).SetValue(item, convertedValue, null);
    }
    else
    {
        //PropertyInfo ipi = pi.PropertyType.GetProperties().Single(p => p.GetIndexParameters().Length > 0);
        //var collection = pi.GetValue(item, index);
        //collection.GetType().GetProperty("Value").SetValue(collection, convertedValue, null);
        var _pi = pi.PropertyType.GetProperty("Item");
        _pi.SetValue(pi, convertedValue, index);
    }
}

How propertyName is obtained isn't shown above, but in the case of an indexed property, it begins its life as "IndexedProperty[10]" for example.

In the comments after that "else" you can see other things I've tried, by reading some other stackoverflow posts and on other forums on how to do this, but I've failed so far. Any ideas?

Casting the property to ObservableCollection isn't feasible, because I want this to be dynamic.

The concept of the whole thing is to have a DataGrid that's data-bound and have paste work correctly by updating the proper properties of each instance, no matter if the properties are indexed or not. Non-indexed properties work fine, but I can't get the ObservableCollection ones to work.

A class with an ObservableCollection<int> as a property doesn't actually have an indexed property in the traditional sense of an indexer. It just has a non-indexed property which itself has an indexer. So you need to use GetValue to start with (without specifying an index) and then fetch the indexer on the result.

Basically, you need to remember that:

foo.People[10] = new Person();

is equivalent to:

var people = foo.People; // Getter
people[10] = new Person(); // Indexed setter

It looks like you were nearly there with this commented out code:

//var collection = pi.GetValue(item, index);
//collection.GetType().GetProperty("Value").SetValue(collection, convertedValue, null);

... but you were applying the index at the wrong point. You want (I think - the question isn't terribly clear):

var collection = pi.GetValue(item, null);
collection.GetType()
          .GetProperty("Item") // Item is the normal name for an indexer
          .SetValue(collection, convertedValue, index);

try this, im not sure if it will work

_pi.SetValue(pi, convertedValue, new object[] { (int) 0 }); 

//where 0 is the index in which you want to insert the value, in this case to index 0

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM