无法将扩展类转换为IList

时间:2016-12-22 20:53:55

标签: c# list

鉴于以下类别:

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上看起来无济于事。

4 个答案:

答案 0 :(得分:3)

该类实现IList<T>,而不是IList。如果您希望它实现IList,您需要将其添加到类的定义中,并为该接口的各种方法添加适当的方法。

答案 1 :(得分:3)

它不会起作用,因为你的课程没有实现IList

  • 它直接实施IList<SomeClass>ICloneableIEquatable<PinList>
  • 间接(via 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

List<T>

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,则第一个将抛出异常。