1

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 (Get the actual type of a generic object parameter) is of help.

Community
  • 1
  • 1
Matt Mitchell
  • 40,943
  • 35
  • 118
  • 185

2 Answers2

4

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;
}
Matt Mitchell
  • 40,943
  • 35
  • 118
  • 185
Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
2

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
  • 23,769
  • 3
  • 56
  • 67
  • 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, List (even leaving out Dictionary). The problem is that you can't cast say listInstance to a List in order to append and even if I created an IEnumerable I can't replace a property field of type List with this new created object. – Matt Mitchell Sep 02 '09 at 08:26
  • 1
    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 Sep 02 '09 at 15:07
  • 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 :-) – Matt Mitchell Sep 03 '09 at 04:05