Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interface as method parameter type works but not List of Interface

Tags:

c#

interface

I have an interface and 2 classes inheriting that interface like below

public interface ILeader
{
    int ID { set; get; }
    string Name { set; get; }
}
public class User : ILeader
{
    public int ID { set; get; }
    public string Name { set; get; }
}
public class Group : ILeader
{
    public int ID { set; get; }
    public string Name { set; get; }
}

Now i have 2 method which has a parameter of type ILeader and IList of ILeader

public void Change(ILeader leader)
{
  //do some thing           
}
public void ChangeList(IList<ILeader> leaderList)
{
  //do some thing           
}

now i can pass an object of either Group or User to Change method and it works. But when i try to do the same with a List to ChangeList method it gives me compile time error.

IList<User> userList=new List<User>();
userList.Add(new User { ID=1, Name ="Happy"});

Change(userList[0]);  //this works

ChangeList(userList);  //this throws compile error

The error is

cannot convert from List<User> to List<ILeader>

How to make my ChangeList method work so that i can pass both a list of Users and Groups ?

like image 510
Happy Avatar asked Nov 02 '12 18:11

Happy


2 Answers

If you are using .Net 4.0 or greater, you can change your IList(T) to an IEnumerable(T) and it will work. The IList(T) interface's T parameter is not covariant and IEnumerable(T) interface's T parameter is. See

http://msdn.microsoft.com/en-us/library/dd469487.aspx

for further explanation.

like image 124
dugas Avatar answered Sep 30 '22 15:09

dugas


Because IList<T> is not covariant, which means there's nothing from stopping ChangeList from adding a Group to the list of Users, which is obviously invalid.

To pass a list of both kinds, convert the list to a List<ILeader>:

ChangeList(userList.Cast<ILeader>().ToList()); 

However be aware that this doesn't actually cast the list, it creates a new list where each member is an instance of ILeader. Which means that ChangeList could add a Group to the list, meaning you couldn't convert it back to a List<User>.

If ChangeList doesn't add any members to the list you can just convert it back:

var leaderList = userList.Cast<ILeader>().ToList();
ChangeList(leaderList);  
userList = leaderList.Cast<User>().ToList();

If ChangeList adds any items other than Users then the conversion will fail. Your best choice is to take only the Users from the result:

var leaderList = userList.Cast<ILeader>().ToList();
ChangeList(leaderList);  
userList = leaderList.OfType<User>().ToList();  // will ignore anything that's not a `User`
like image 44
D Stanley Avatar answered Sep 30 '22 14:09

D Stanley