如何将 List<T> 投射到我自己的 Collection

How to Cast List<T> to my own Collection

出于各种原因,我实现了自己的 collection class。 如何避免在 ItemCollection resultCollection = (ItemCollection)list; 上投射失败?我继承自 List<T>,所以我不能投射吗?我可以修改我的 BaseEntityCollection 使其能够执行此操作吗?

static class Program
{
    static void Main()
    {
        ItemCollection collection = new ItemCollection();
        Item item = new Item();
        item.ID = 1;
        item.Name = "John";
        collection.Add(item);
        List<Item> list = collection.FindAll(x => x.ID == 1 && x.Name == "John");

        ItemCollection resultCollection = (ItemCollection)list; // It's breaking here
    }
}


public class ItemCollection : BaseEntityCollection<Item>
{
}

public class Item : BaseEntity
{
    public int ID { get; set; }
    public string Name { get; set; }
}

public abstract class BaseEntityCollection<T> : List<T>, IEnumerable<T> where T : BaseEntity, new()
{
}

public abstract class BaseEntity
{
}

我知道我可以在 ItemCollection 上单独实现 FindAll 但我想利用 List<T>.

上可用的所有方法

我也知道我能做到list.ForEach(resultCollection.Add);。但这意味着我想避免再次迭代 collection。

只需更改您的构造函数,以便您可以使用 List<Item> 集合对其进行初始化。这使您可以使用另一个集合初始化项目集合:

static class Program
{
    static void Main()
    {
        ItemCollection collection = new ItemCollection();
        Item item = new Item();
        item.ID = 1;
        item.Name = "John";
        collection.Add(item);
        List<Item> list = collection.FindAll(x => x.ID == 1 && x.Name == "John");

        ItemCollection resultCollection = new ItemCollection(list);
    }
}


public class ItemCollection : BaseEntityCollection<Item>
{
    //Allow default constructor
    public ItemCollection() { }

    //Construct with a list collection
    public ItemCollection(IEnumerable<Item> collection)
        : base(collection)
    {

    }
}

public class Item : BaseEntity
{
    public int ID { get; set; }
    public string Name { get; set; }
}

public abstract class BaseEntityCollection<T> : List<T>, IEnumerable<T> where T : BaseEntity, new()
{
    //Still be able to create blank items
    public BaseEntityCollection() { }

    public BaseEntityCollection(IEnumerable<T> collection)
        : base(collection)
    {

    }
}

public abstract class BaseEntity
{
}

为了避免重复您的列表两次,我将更改以下内容:

List<Item> list = collection.FindAll(x => x.ID == 1 && x.Name == "John");

var list = collection.Where(x => x.ID == 1 && x.Name == "John");

这将延迟加载您的列表(在某种程度上),但它只会在您从中创建新的 ItemCollection 时迭代您的集合一次。

ItemCollection resultCollection = new ItemCollection();
resultCollection.AddRange(collection.Where(x => x.ID == 1 && x.Name == "John"));

如果您碰巧没有 AddRange 扩展方法,请制作它。

void AddRange<T>(this ItemCollection c, IEnumerable<T> items) => foreach(T i in items) c.Add(i);

增加已经很好的答案。你问:

I'm inheriting from List so shouldn't I be able to cast?

是也不是。

您的特定转换在编译时有效,但在运行时无效。

转换是一种告诉编译器的方式,"Trust me. This will work at runtime."

在运行时,只有当 Base 中的底层对象实际上是Descendant.

类型的对象

例如,请记住 stringobject 的后代,下面是您的转换在运行时失败的原因的说明。

// builds but fails at runtime
object o1 = new object();
string s1 = (string)o1;     

// builds and works at runtime
// because o2 is a string in object's clothing
object o2 = (object)"";
string s2 = (string)o2;