3

I'm trying to use reflection to add an unknown object to an unknown collection type, and I'm getting an exception when I actually perform the "Add". I wonder if anyone can point out what I'm doing wrong or an alternative?

My basic approach is to iterate through an IEnumerable which was retrieved through reflection, and then adding new items to a secondary collection I can use later as the replacement collection (containing some updated values):

IEnumerable businessObjectCollection = businessObject as IEnumerable;
Type customList = typeof(List<>)
       .MakeGenericType(businessObjectCollection.GetType());
var newCollection = (System.Collections.IList)
          Activator.CreateInstance(customList);

foreach (EntityBase entity in businessObjectCollection)
{
// This is the area where the code is causing an exception
    newCollection.GetType().GetMethod("Add")
         .Invoke(newCollection, new object[] { entity });
}

The exception is:

Object of type 'Eclipsys.Enterprise.Entities.Registration.VisitLite' cannot be converted to type 'System.Collections.Generic.List`1[Eclipsys.Enterprise.Entities.Registration.VisitLite]'.

If I use this line of code for the Add() instead, I get a different exception:

newCollection.Add(entity); 

The exception is:

The value "" is not of type "System.Collections.Generic.List`1[Eclipsys.Enterprise.Entities.Registration.VisitLite]" and cannot be used in this generic collection.

Jonathan Nixon
  • 4,940
  • 5
  • 39
  • 53
Dustin Kofoed
  • 539
  • 1
  • 8
  • 17
  • 4
    According to a first exception you are trying to cast "Eclipsys.Enterprise.Entities.Registration.VisitLite" to "List<>". I think that's your problem. – Dilshod Sep 24 '13 at 16:34
  • 2
    Why would you do this? use proper generics. Having to use reflection for such a common task is an indication that you're putting all this code in the wrong place. – Federico Berasategui Sep 24 '13 at 16:35
  • And what is the point of casting if you are using reflection? – Dilshod Sep 24 '13 at 16:36
  • If all of your collection types has a Add method then just use dynamic. – Dilshod Sep 24 '13 at 16:39
  • Except in rare and unusual circumstances, if you find yourself resorting to lots of reflection and dynamics in your code, you're likely doing something horribly horribly wrong! – Alan Sep 24 '13 at 16:42
  • Side note: I've removed unrelated/commented code. Next time please try to make sample smaller as recommended in http://www.sscce.org – Alexei Levenkov Sep 24 '13 at 16:47
  • @Dilshod - you should post your first comment as an answer. – Alexei Levenkov Sep 24 '13 at 16:48
  • What I would actually prefer to do is use the SetValue() method on a collection in order to set the value of one of the items in the collection to a different object ... I just can't figure out how to use SetValue() on a collection object. – Dustin Kofoed Sep 24 '13 at 18:28

1 Answers1

5

According to a first exception you are trying to cast Eclipsys.Enterprise.Entities.Registration.VisitLite to List<>. I think that's your problem.

Try this:

 businessObject = //your collection;
 //there might be two Add methods. Make sure you get the one which has one parameter.
 MethodInfo addMethod = businessObject.GetType().GetMethods()
.Where(m => m.Name == "Add" && m.GetParameters().Count() == 1).FirstOrDefault();
 foreach(object obj in businessObject as IEnumerable)
 {
     addMethod.Invoke(businessObject, new object[] { obj });
 }
Dilshod
  • 3,189
  • 3
  • 36
  • 67
  • Thanks for the response ... I still get the same exception using the above MethodInfo code though: Object of type 'Eclipsys.Enterprise.Entities.Registration.VisitLite' cannot be converted to type 'System.Collections.Generic.List`1[Eclipsys.Enterprise.Entities.Registration.VisitLite]'. – Dustin Kofoed Sep 24 '13 at 18:26
  • My bad - the exception is actually different. It's actually "object does not match target type". I tried casting it to the exact same type it's looking for in one instance, but still get that same error. ` Eclipsys.Enterprise.Entities.Registration.VisitLite visit = (Eclipsys.Enterprise.Entities.Registration.VisitLite)o; MethodInfo addMethod = businessObject.GetType().GetMethod("Add"); addMethod.Invoke(newCollection, new object[] { visit }); ` – Dustin Kofoed Sep 24 '13 at 18:39
  • @DustinKofoed Change this line: addMethod.Invoke(newCollection, new object[] { visit }); to addMethod.Invoke(businessObject, new object[] { visit }); Then let me know what happens. – Dilshod Sep 24 '13 at 21:34
  • Thanks ... i actually ended up approaching this a different way. [link](http://stackoverflow.com/questions/18990705/how-to-modify-a-specific-item-in-a-collection-using-reflection) – Dustin Kofoed Sep 24 '13 at 23:24
  • You can rewrite `MethodInfo addMethod = .....` as `MethodInfo addMethod = businessObject.GetType().GetMethods().FirstOrDefault(m => m.Name == "Add" && m.GetParameters().Count() == 1);` – Athafoud Aug 30 '16 at 12:40