作为方法参数类型的接口可以工作但不能接口列表

Hap*_*ppy 5 c# interface

我有一个接口和2个继承该接口的类,如下所示

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; }
}
Run Code Online (Sandbox Code Playgroud)

现在我有2个方法,它有一个类型的参数ILeader和ILeader的IList

public void Change(ILeader leader)
{
  //do some thing           
}
public void ChangeList(IList<ILeader> leaderList)
{
  //do some thing           
}
Run Code Online (Sandbox Code Playgroud)

现在我可以传递任何一个对象GroupUser改变方法,它的工作原理.但是,当我尝试使用Listto ChangeList方法执行相同操作时,它会给出编译时错误.

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
Run Code Online (Sandbox Code Playgroud)

错误是

cannot convert from List<User> to List<ILeader>
Run Code Online (Sandbox Code Playgroud)

如何使我的ChangeList方法工作,以便我可以传递一个列表UsersGroups

dug*_*gas 5

如果您使用的是.Net 4.0或更高版本,则可以将IList(T)更改为IEnumerable(T),它将起作用.IList(T)接口的T参数不是协变的,IEnumerable(T)接口的T参数是.看到

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

进一步解释.


D S*_*ley 5

因为IList<T>不是协变,这意味着没有什么可以阻止ChangeList添加Group到列表中Users,这显然是无效的.

要传递两种类型的列表,请将列表转换为List<ILeader>:

ChangeList(userList.Cast<ILeader>().ToList()); 
Run Code Online (Sandbox Code Playgroud)

但请注意,这实际上并没有强制转换列表,而是创建一个列表,其中每个成员都是一个实例ILeader.这意味着ChangeList可以添加Group到列表中,这意味着您无法将其转换回List<User>.

如果ChangeList没有将任何成员添加到列表中,您可以将其转换回来:

var leaderList = userList.Cast<ILeader>().ToList();
ChangeList(leaderList);  
userList = leaderList.Cast<User>().ToList();
Run Code Online (Sandbox Code Playgroud)

如果ChangeList 添加Users 之外的任何项目,则转换将失败.你最好的选择是从结果中Users:

var leaderList = userList.Cast<ILeader>().ToList();
ChangeList(leaderList);  
userList = leaderList.OfType<User>().ToList();  // will ignore anything that's not a `User`
Run Code Online (Sandbox Code Playgroud)