views:

664

answers:

2

Hi,

I need to be able to access a property via reflection, and, knowing that this property is an IEnumerable, append an object to it.

Something like this:

Object o;
MemberInfo m;

Array arr; // Except use IEnumerable, may have to take account of value/ref types
arr = (Array)((PropertyInfo)m).GetValue(o, null); }

List<o.GetType()> newArr = new List<o.GetType()>(); /* fails */
newArr.AddRange(arr);
newArr.Add(o);

((PropertyInfo)m).SetValue(o, newArr.ToArray(), null);

Can you help me where I'm going wrong :-)

Solution:

See accepted answer comments. Also (http://stackoverflow.com/questions/1371347/get-the-actual-type-of-a-generic-object-parameter/1371378#1371378) is of help.

+1  A: 

It sounds like you're essentially asking how to make a List<T> based on an unknown-at-compile-time type. For this you'll have to use a bit more reflection magic:

Type genericListType = typeof(List<>);
Type listType = genericListType.MakeGenericType(o.GetType());
object listInstance = Activator.CreateInstance(listType);

That would create a List<T> out of a runtime type.

But really, your code would be much simpler if you simply use ArrayList:

ArrayList list = new ArrayList(arr);
list.Add(o);
Array newArray = list.ToArray(o.GetType());
bobbymcr
Thanks for pointing me in the right direction. Unfortunately I don't think I can write a generic solution that deals with properties of string[], List<string>, List<RandomObject> (even leaving out Dictionary<k,v>). The problem is that you can't cast say listInstance to a List<T> in order to append and even if I created an IEnumerable<T> I can't replace a property field of type List<T> with this new created object.
Graphain
Is it possible to step back and consider the overall problem you are solving, to see if you can make use of a more compile-time friendly approach? Reflection is powerful but ends up being complicated and hard to maintain.If you can't change what you are doing, there still is a way to support everything you mentioned, it just requires ugly reflection code. I would probably forget about replacing the underlying reference and just look for an Add method that I could use (e.g. propertyType.GetMethod("Add")) and then special-case handling of arrays.
bobbymcr
It's for generically mapping code classes against a data file so reflection has to be the answer. Thanks, though, in combination your idea and this question (http://stackoverflow.com/questions/1371347/get-the-actual-type-of-a-generic-object-parameter/1371378#1371378) + handling of Arrays helped :-)
Graphain
+2  A: 

Once you have an IEnumerable type, use something like this to append to it:

public static IEnumerable<T> Append<T>(this IEnumerable<T> original, T next)
{
    foreach (T item in original) yield return item;
    yield return next;
}

public static IEnumerable<T> Append<T>(this IEnumerable<T> original, params T[] next)
{
    foreach (T item in original) yield return item;
    foreach (T item in next) yield return item;
}

public static IEnumerable<T> Append<T>(this IEnumerable<T> original, IEnumerable<T> next)
{
    foreach (T item in original) yield return item;
    foreach (T item in next) yield return item;
}
Joel Coehoorn
Thanks for that :-)
Graphain
Though you have to rename those methods Append<T>
Graphain