vendredi 8 juillet 2022

Concatenating Lists at runtime

I am handling classes that wrap collections. For example:

public class CollA 
{
  public List<SomeType> Items {get;set;}

  // other properties I'm not interested in
}

I am guaranteed that the collection classes will have exactly ONE property that is of List<T>

Now, I find myself with a requirement such that I may have many instances of CollA and I am asked to return a new instance of CollA where the property Items contains a union of the Items properties of the individual CollA instances. So, for example:

var A = new CollA(Items = new List<SomeType> 
{
  new SomeType("A"), new SomeType("B")
};
var B = new CollA(Items = new List<SomeType> 
{
  new SomeType("C"), new SomeType("D")
};

var result = SomeMythicalCombine(A, B);

// result.Items == { new SomeType("A"), new SomeType("B"), new SomeType("C"), new SomeType("D") }

This, if the types are all known at compile time is easy, but I need to do it with the types not being known until runtime.

I've got part of the way, I think, using reflection....

public T SomeMythicalCombine (params object[] collections)
{
    var collectionType = typeof(T);
    
    var listProperty = collectionType.GetProperties()
        .Single(p=> typeof(IList).IsAssignableFrom(p.PropertyType));

    var listPropertyName = listProperty.Name;

    var result = Activator.CreateInstance(collectionType);

    var innerType = listProperty.PropertyType.GenericTypeArguments[0];
    var listType = typeof(List<>).MakeGenericType(innerType);
    var list = Activator.CreateInstance(listType);
    
    foreach(var collection in collections)
    {
        var listValues = collection.GetType().GetProperty(listPropertyName).GetValue(collection);
        
        // listItems is an object here and I need to find a way of casting it
        // to something I can iterate over so I can call (list as IList).Add(something)
    }   
    
    // Then, I think, all I need to do is set the appropriate property on the 
    // the result item
    result.GetType().GetProperty(listPropertyName).SetValue(result, list);
    
    return result as T;
}

Can anyone fill in the gap in my thinking, please?





Aucun commentaire:

Enregistrer un commentaire