B.K.
B.K.

Reputation: 10162

Iterating through fields, which are lists, of an abstract class and passing them to a method of type T?

I have a class that contains a number of lists:

public static class CollectionsClass
{

    public static List<Object1> list1 = new List<Object1>();
    public static List<Object2> list2 = new List<Object2>();
    public static List<Object3> list3 = new List<Object3>();
}

I also have a class that performs actions on those lists:

public static class ActionClass
{
    private static Random _rnd = new Random();

    public static void PopulateCollections()
    {
        Populate(list1, 0, 1000);
        Populate(list2, 0, 1000);
        Populate(list3, 0, 1000);
    }           

    private static void Populate<T>(List<T> list, int minLimit, int maxLimit) 
        where T: new()
    {
        int popSize = _rnd.Next(minLimit, maxLimit);
        for (int i = 0; i < popSize; i++)
        {
            list.Add(new T());
        }
    }
}

Because the number of lists may change, what I would like to do is something like this:

    public static void PopulateCollections()
    {
        var fields = typeof(CollectionsClass).GetFields();
        foreach (var field in fields)
        {
            Populate(field, 0, 1000);
        }
    }

Unfortunately, that gives me an error:

The type arguments for method 'app.ActionClass.Populate (System.Collections.Generic.List, int, int)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

So, there's obviously some problem with it not knowing what type I'm passing... but I thought that it'd be obvious from field.

Upvotes: 0

Views: 347

Answers (2)

Dmitry
Dmitry

Reputation: 14059

I've used reflection for that:

public static class CollectionsClass
{
    public static List<Object1> list1 = new List<Object1>();
    public static List<Object2> list2 = new List<Object2>();
    public static List<Object3> list3 = new List<Object3>();
}

public static class ActionClass
{
    private static void Populate<T>(List<T> list, int minLimit, int maxLimit)
        where T : new()
    {
        var rnd = new Random();
        int rndNum = rnd.Next(minLimit, maxLimit);
        for (int i = 0; i < rndNum; i++)
        {
            list.Add(new T());
        }
    }

    public static void PopulateCollections()
    {
        var fields = typeof(CollectionsClass).GetFields(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);
        foreach (var field in fields)
        {
            var method = typeof(ActionClass).GetMethod("Populate", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).MakeGenericMethod(field.FieldType.GenericTypeArguments[0]);
            method.Invoke(null, System.Reflection.BindingFlags.Static, null, new object[] { field.GetValue(null), 0, 1000 }, Thread.CurrentThread.CurrentCulture);
        }
    }
}

Upvotes: 0

Kris Vandermotten
Kris Vandermotten

Reputation: 10201

You can get the value of a field, for which you have a FieldInfo object, using the GetValue method. Then you need to call the generic method with the correct type parameter. While that can be constructed using reflection, I suggest you try dynamic programming:

public static void PopulateCollections()
{
    var fields = typeof(CollectionsClass).GetFields();
    foreach (var fieldInfo in fields)
    {
        dynamic field = fieldInfo.GetValue(null);
        Populate(field, 0, 1000);
    }
}

The code above assumes that those fields are all static, and that there are no other fields than those of type List<T>.

Upvotes: 1

Related Questions