Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SetValue of Indexed Property in C# using Reflection

Tags:

c#

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.

like image 617
Lefteris Aslanoglou Avatar asked Dec 27 '12 10:12

Lefteris Aslanoglou


People also ask

What is the use of SetValue?

SetValue(Object, Object, Object[]) Sets the property value of a specified object with optional index values for index properties.

How does reflection set property value?

To set property values via Reflection, you must use the Type. GetProperty() method, then invoke the PropertyInfo. SetValue() method. The default overload that we used accepts the object in which to set the property value, the value itself, and an object array, which in our example is null.

What is reflection in programming C#?

Reflection provides objects (of type Type) that describe assemblies, modules, and types. You can use reflection to dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties.


1 Answers

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);
like image 65
Jon Skeet Avatar answered Sep 28 '22 16:09

Jon Skeet