鉴于以下类别:
public class MyList<T> : IList<T>, ICloneable
{ ... }
public class PinList : MyList<SomeClass>, ICloneable, IEquatable<PinList>
{ ... }
为什么不这样做?
public void Main()
{
PinList pins = new PinList();
Method2(pins); // Does not work
List<string> strings = new List<string>();
Method2(strings); // WORKS
}
public void Method2(object obj)
{
// returns TRUE
obj.GetType().GetInterfaces().Any(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IList<>));
var things = ((IList)obj).Cast<object>().ToList();
// Unable to cast object of type 'PinList' to type 'System.Collections.IList'.
}
我已经尝试将obj强制转换为obj.GetType(),而且我在google上看起来无济于事。
答案 0 :(得分:3)
该类实现IList<T>
,而不是IList
。如果您希望它实现IList
,您需要将其添加到类的定义中,并为该接口的各种方法添加适当的方法。
答案 1 :(得分:3)
它不会起作用,因为你的课程没有实现IList
。
IList<SomeClass>
,ICloneable
和IEquatable<PinList>
。IList<SomeClass>
)实施ICollection<SomeClass>
,IEnumerable<SomeClass>
和IEnumerable
。有人可能希望IList<T>
实现IList
,但事实并非如此。如果你考虑一下,这是有道理的:IList
保证可以将任意对象添加到列表中。但是,IList<T>
仅允许添加类型为T
的对象或其子类型。因此,如果IList<T>
实施IList
,则会违反Liskov substitution principle。
IEnumerable
您没有遇到此问题,因为无法将项添加到IEnumerable
。因此,IEnumerable<T>
满足IEnumerable
满足的所有合同,因此IEnumerable<T>
实现IEnumerable
。
答案 2 :(得分:1)
只需hint:
public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable
public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>,
IEnumerable, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>
我在IList
上看到了List<T>
,但IList<T>
还没有实现IList
!
查看自定义列表派生类签名:
public class PinList : MyList<SomeClass>, ICloneable, IEquatable<PinList>
当我看到IEquatable<PinList>
时,我感到很惊讶。您是否尝试实施自定义列表只是因为您希望能够确定两个类型PinList
的给定列表是否具有相同的项目?
HashSet<T>
救援!请参阅此其他问答:Check if two list have the same items
也许您还在实施自定义列表只是因为您希望能够将其设为 cloneable ,我会说这是一个糟糕的设计决策。
list.ToList()
就足够了。list.Select(o => (SomeType)o.Clone()).ToList()
。显然,存储的对象应该实现ICloneable
。另一方面,如果您认为自己不想重复,可以使用扩展方法:public static class ListExtensions
{
public static IList<T> CloneList<T>(this IList<T> source)
where T : ICloneable
=> source.Select(o => (T)o.Clone()).ToList();
}
...并在任意位置拨打电话:list.CloneList()
。
所以......不再需要实施IList<T>
或派生List<T>
了!
答案 3 :(得分:1)
你PinList实现了IList&lt; T&gt;,但是你试图将obj强制转换为IList。
的IList&LT; T&GT;和IList是两个不同的接口。
将班级更改为
public class MyList<T> : IList, ICloneable
{ ... }
你将能够将obj转换为IList。
转换时,您不需要这个长语句
var things = ((IList)obj).Cast<object>().ToList();
只是
IList things = (IList)obj;
或
IList things = obj as IList;
将完成你的工作。如果obj不能转换为IList而第二个只返回null,则第一个将抛出异常。