无法将通用列表转换为自定义列表类型

5

我有两个类:

public class MyClass
{
    public int Foo { get; set; }
    public string Bar { get; set; }
}

public class MyList : List<MyClass>
{
}

在其他代码中,我正在为来自数据库的每个记录创建MyClass的实例,并希望将它们全部返回到MyList的实例中:

var records = _repository.GetRecords();
return (MyList) records.Select(x => x.ConvertTo<MyClass>()).ToList();

代码编译没有问题,但是抛出了一个运行时InvalidCastException异常:

无法将类型为“System.Collections.Generic.List`1[MyClass]”的对象强制转换为类型“MyList”。

我不明白为什么会出现这个错误,因为MyList 就是一个List<MyClass>
我找到了一些相关的问题,都涉及到协变性。 这个问题与我的问题最相似,但我不知道如何适应答案来解决我的问题。 我的问题:
如何从数据库记录构建一个MyList实例?
我正在使用C#和.NET 4.0。

2
List<MyClass> 不会自动变成 MyList。但是你可以创建一个构造函数,接受一个 List<MyClass> - It'sNotALie.
一个子类属于它的父类类型,反之则不成立。一个父类可以有很多个子类 - Andre Calil
CA1002: 不要公开泛型列表 -- http://msdn.microsoft.com/zh-cn/library/ms182142(v=vs.80).aspx ... 记住这一点。 - myermian
2个回答

9
每个 MyList 都是一个 List<MyClass>,但并不是每个 List<MyClass> 都是一个 MyList。例如,如果您在 MyList 上有自定义属性,则 Linq 的 ToList 方法将不会知道它。
您可以使用 List<T> 的复制构造函数来创建一个新的 MyList
return new MyList(records.Select(x => x.ConvertTo<MyClass>()).ToList());

编辑

正如@ekolis敏锐地指出的那样,您需要明确“继承”List<T>的拷贝构造函数:

public class MyList : List<MyClass>
{
    public MyList(IEnumerable<MyClass> list)
        : base(list)
    {
    }
}

我建议您先退一步思考,看看您是否真的需要一个MyList类,或者您可以只使用List<MyClass>(甚至只是IEnumerable<MyClass>)。


2
请注意,您实际上需要创建此复制构造函数;它不会从List<T>继承。 - ekolis
MyList 类被序列化为 XML。我使用它来代替普通的 List<MyClass>,因为后者会生成一个名为 "ArrayOfMyClass" 的 XML 元素,而我想要能够控制 XML 元素的名称以便自定义,例如在这种情况下是 "MyList"。 - Jesse Webb

0

你可以将派生类转换为基类,但反过来不行。 如果你有这个:

public class Base {}
public class Derived : Base {}

你可以将 Derived 强制转换为 Base,但你不能将 Base 强制转换为 Derived

Base b = (Base)new Derived();

能工作 但不是最佳方案

Derived d = (Derived)new Base();

Derived类可能比Base类包含更多信息,这就是为什么。

在您的情况下,@D Stanley给出了解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接