我有一个接口和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)
现在我可以传递任何一个对象Group
或User
改变方法,它的工作原理.但是,当我尝试使用List
to 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
方法工作,以便我可以传递一个列表Users
和Groups
?
如果您使用的是.Net 4.0或更高版本,则可以将IList(T)更改为IEnumerable(T),它将起作用.IList(T)接口的T参数不是协变的,IEnumerable(T)接口的T参数是.看到
http://msdn.microsoft.com/en-us/library/dd469487.aspx
进一步解释.
因为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
添加除User
s 之外的任何项目,则转换将失败.你最好的选择是从结果中只取User
s:
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)