将派生类List传入基类List参数方法报错及泛型访问问题咨询
先给你拆解下两个问题的核心:
第一个错误——List<Family>转不了List<Client>,是因为**List<T>是「不变类型」**。哪怕Family是Client的子类,List<Family>和List<Client>也不属于继承关系。C#这么设计是为了类型安全:要是允许这种转换,你的SortEarlyToLate方法里万一往列表里加个Helper实例,原来的List<Family>根本装不下,直接就炸了。
然后是你用泛型方法时遇到的属性访问问题——其实这是可以解决的,你大概率是写法上有小疏漏。只要给泛型方法加上正确的类型约束,完全能正常访问基类的Start和End属性。
最优解决方案(不用转类型也不用重复写方法)
1. 修正泛型方法(首推)
给泛型方法加上where T : Client约束后,T就被限定为Client或它的子类,所以你可以直接通过T实例访问基类的公共成员。正确的写法应该是这样:
static void SortEarlyToLate<T>(List<T> clientList) where T : Client { // 排序示例:直接用Start属性比较完全没问题 clientList.Sort((clientA, clientB) => clientA.Start.CompareTo(clientB.Start)); // 修改属性也一样顺畅 foreach (var client in clientList) { client.Start += 15; // 随便改基类的公共属性 } }
现在调用SortEarlyToLate(familySchedule)就完全合法,而且不会有属性访问错误。你之前遇到的报错,可能是拼写错了属性名,或者不小心把基类的成员修饰符改了?不过按你说的基类里是public的,那应该是写法上的小问题,按上面的代码调整就行。
2. 用协变接口IEnumerable<Client>(适合只读场景)
如果你的方法只需要读取、遍历元素,不需要修改列表的结构(比如添加/删除元素),可以把方法参数改成IEnumerable<Client>。因为IEnumerable<T>是协变的,List<Family>可以直接隐式转换成IEnumerable<Client>:
static void SortEarlyToLate(IEnumerable<Client> clientList) { // 注意:IEnumerable是只读的,要排序得先转成List/数组 var sortedClients = clientList.OrderBy(c => c.Start).ToList(); // 修改属性还是正常操作 foreach (var client in sortedClients) { client.End -= 5; } }
但如果你的方法需要修改原列表的结构(比如插入新元素),这种方式就不适用了,毕竟IEnumerable不支持结构修改。
额外唠两句
泛型方法之所以能解决问题,是因为where T : Client既保证了类型安全(不会往List<Family>里塞Helper),又让你能无缝访问基类的公共成员。而List<T>的不变性是C#的安全机制,别觉得是设计缺陷——它是在帮你避免潜在的类型错误。
内容的提问来源于stack exchange,提问作者half of a glazier

