简体   繁体   中英

Add to list when list type is not known until runtime

I have method which accepts an object . This object I know is a List<T> however T may vary between children of a base class at any one time when being passed into the method.

So if my base class is MonthType , and I have children called BlockMonthType and AreaMonthType the object passed in could be anyone of List<BlockMonthType> or List<AreaMonthType> .

I want to be able to add items to this object however when I cast it it seems to make a copy and the original object is not updated.

I'm doing this to cast:

var objectList = ((IEnumerable<MonthType>)graphObject.Source.Object).ToList();

Now I want to create a new item and add it to the list

// where ObjectType is a Type variable containing BlockMonthType
var newObject = (BlockMonthType)Activator.CreateInstance(graphObject.Source.ObjectType);

objectList.Add(newObject);

// and carry on the world is good

This works in so far as objectList has a newObject added. However the original variable isn't updated so when I leave the method it's back to it's original state. I know the object is a List<> when passed in as I can see it in the debugger as such.

Is there anyway I can accomplish this?

Here is a cut down version of the method I'm using it in.

public TraverseGraphResult Write(ObjectGraph graphObject)
{
    var objectList = ((IEnumerable<MonthType>)graphObject.Source.Object).ToList();

    var newObject = (MonthType)Activator.CreateInstance(rule.ObjectType);
    newObject.Month = rule.Month;

    objectList.Add(newObject);

    // Other stuff as well is done but that's the crux of it
}

Hopefully this gives it more context. The method is being used to try and navigate a large object tree with many class types. I'm trying to add a new class type handler which will deal with adding and removing items from a list.

// This is being used in a recursive method to loop down a object's property tree

// .. more code here

// where properties is a List<PropertyInfo>
foreach (var pInfo in properties)
{
    if (IsList(pInfo.PropertyType))
    {
        var enumerable = (IEnumerable)pInfo.GetValue(currentObjectGraph.Source.Object, null);

        var sourceEnumerator = enumerable.GetEnumerator();          
        var graph = new ObjectGraph(enumerable, pInfo.Name);

        // this part is made up but essentially the code looks up a list of objects that can deal with this 
        // particular one and returns it.  We then call the write method on that object
        var something = GetInterfaceHandlerForObject(enumerable);
        something.Write(graph);
    }
}

You should make your method generic:

public void MyMethod<T>(List<T> objectList) where T:class, new()
{
    objectList.Add(new T());
    ...
}

Casting is rarely ever necessary when you use generics. Also, your ToList() is causing a new copy of the list to be created.

One drawback to this approach is that T needs to have an empty constructor. If you need to construct an object with parameters you could instead pass in a Func<T> . You can then call it passing in a lambda expression like: (x) => new BlockMonthType(someParameter, orAnother) .

I ended up resolving this by storing the underlying List T type in the ObjectGraph object and casting to that when required.

var objectList = ((IEnumerable)graphObject.Source.Object).Cast(monthAllocationRule.ListType);

Without the correct cast objectList was either null or a copy of the list. Now I can add to objectList and know it's added to the source object.

Probably not idea as Ian mentioned above but did the trick.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM