views:

45

answers:

1

I have need to cast a generic list of a concrete type to a generic list of an interface that the concrete types implement. This interface list is a property on an object and I am assigning the value using reflection. I only know the value at runtime. Below is a simple code example of what I am trying to accomplish:

public void EmployeeTest()
    {
        IList<Employee> initialStaff = new List<Employee> { new Employee("John Smith"), new Employee("Jane Doe") };
        Company testCompany = new Company("Acme Inc");
        //testCompany.Staff = initialStaff;

        PropertyInfo staffProperty = testCompany.GetType().GetProperty("Staff");
        staffProperty.SetValue(testCompany, (staffProperty.PropertyType)initialStaff, null);
    }

Classes are defined like so:

public class Company
{
    private string _name;

    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }

    private IList<IEmployee> _staff;

    public IList<IEmployee> Staff
    {
        get { return _staff; }
        set { _staff = value; }
    }

    public Company(string name)
    {
        _name = name;
    }
}

public class Employee : IEmployee
{
    private string _name;

    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }

    public Employee(string name)
    {
        _name = name;
    }
}

public interface IEmployee
{
    string Name { get; set; }
}

Any thoughts?

I am using .NET 4.0. Would the new covariant or contravariant features help?

Thanks in advance.

+3  A: 

No, .NET 4 variance won't help here: IList<T> is invariant, as values go both in and out (you can add items and you can fetch them).

Basically this cast is not going to work (unless you use an array and its variance properties; that's just horrible though). The cast itself isn't necessary - SetValue just takes object - but the attempt to set the propert with the wrong type will fail.

You could build a new list of the right type - but that means it will be separate from the existing list. Is that acceptable? (The list elements themselves would be shared, but if you added a new element to one list, it wouldn't be shown in the other.)

Jon Skeet
The list would be new, but the employees would be the same old objects
SWeko
@SWeko: Absolutely. Will edit to make that clearer.
Jon Skeet
To additionally complicate the matter, Staff is an IList, so you cannot just instantiate it, and add the new elements, you have to know the desired implementation too...
SWeko
@SWeko: Indeed - I was assuming a `List<T>` would suffice there :)
Jon Skeet