Search code examples
c#reflection

Get elements of list of unknown type through Reflection


I have types that looks like the following:

public class Test1
{
    [SubTests]
    List<SubTest1> SubTests { get; set; } = [];

    public void Run()
    {
        foreach(var subtest in SubTests)
        {
             // ...
        }
    }

    public class SubTest1 : ISubTest { }
}
public class Test2
{
    [SubTests]
    List<SubTest2> SubTests { get; set; } = [];

    public void Run()
    {
        foreach(var subtest in SubTests)
        {
             // ...
        }
    }

    public class SubTest2 : ISubTest { }
}

public interface ISubTest { }

I want to use reflection to add the elements of Test.SubTests to a BindingList<ISubTest>, but I don't know the type of the ISubTest at compile time.

I tried getting the list like this:

foreach (var property in type.GetProperties())
{
    if (property.GetCustomAttribute<SubTestsAttribute>() != null)
    {
        var subTests = (IList<ISubStep>)property.GetValue(valueSource);
        return new BindingList<ISubstep>(subTests)
    }
}

But that throws an InvalidCastException because the type of the generic parameter to IList<> is different.

Is there any way to do what I'm trying to do?


Solution

  • I think you need to manually add elements with foreach. IList<T> is not covariant (no out).

    foreach (var property in type.GetProperties()) {
        if (property.GetCustomAttribute<SubTestsAttribute>() != null) {
            var subTests = (IEnumerable<ISubStep>)property.GetValue(valueSource);
            var bindingList= new BindingList<ISubstep>();
            foreach (var element in subTests) {
                bindingList.Add(element);
            }
            return bindingList;
        }
    }
    

    EDIT: FWIW, I didn't know this was a duplicate when answering - but thanks for the two downvotes. That definitely should teach me a lesson in what the "consensus" is.