An interface as a type of method parameter works, but not an interface list

I have an interface and 2 classes inheriting this interface as shown 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 methods that have a parameter of type ILeader and IList ILeader

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

Now I can pass the Group or User method object to change, and it works. But when I try to do the same with the List to ChangeList , it gives me a 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 

Error

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

How do I get my ChangeList method ChangeList work so that I can pass in both the Users and Groups list?

+4
source share
4 answers

If you use .Net 4.0 or higher, you can change your IList (T) to IEnumerable (T) and it will work. The T parameter of the IList (T) interface interface is not covariant and the T parameter of the IEnumerable (T) interface. Cm

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

for further explanation.

+5
source

Because IList<T> not covariant, which means that there is nothing from stopping ChangeList from adding Group to the Users list, which is clearly invalid.

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

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

However, keep in mind that this does not actually list, it creates a new list where each member is an instance of ILeader . This means that ChangeList can add Group to the list, which means you cannot convert it back to List<User> .

If ChangeList does not add any members to the list, you can simply return it back:

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

If ChangeList adds any elements other than User , then the conversion will fail. Your best bet is to extract only User from the result:

 var leaderList = userList.Cast<ILeader>().ToList(); ChangeList(leaderList); userList = leaderList.OfType<User>().ToList(); // will ignore anything that not a `User` 
+4
source

You should rely on a generic type constraint on your second method:

 public void ChangeList<T>(IList<T> leaderList) where T : ILeader { //do some thing } 

Now you can pass both lists.

+3
source

In C #, classes are not covariant, and this is the function you are trying to use here. See this FAQ for more information on this.

A few important rules to remember:

This feature only works for common interfaces and delegates. If you are implementing a universal generic interface, the implementation class still remains unchanged. Classes and structures do not support variance in C # 4.0. Therefore, the following does not compile:

 // List<T> implements the covariant interface // IEnumerable<out T>. But classes are invariant. List<Person> list = new List<Employee>(); // Compiler error here. 

To do this, you need to give User to ILeader . You would do this with userList.Cast<ILeader>() .

+2
source

Source: https://habr.com/ru/post/1443721/


All Articles