【问题标题】:C# - Why can I not cast a List<MyObject> to a class that inherits from List<MyObject>?C# - 为什么我不能将 List<MyObject> 强制转换为从 List<MyObject> 继承的类?
【发布时间】:2009-04-20 13:23:44
【问题描述】:

我有一个对象,我将其称为 MyObject。它是一个控制特定数据行的类。

然后我有一个集合类,称为 MyObjectCollection:

public class MyObjectCollection : List<MyObject> {}

为什么我不能执行以下操作:

List<MyObject> list = this.DoSomethingHere();
MyObjectCollection collection = (MyObjectCollection)list;

提前致谢。

编辑:错误是 InvalidCastException

【问题讨论】:

  • 糟糕,关闭太快了。看起来和平常不太一样。
  • 我们需要更多才能得到一个好的答案。你得到一个编译错误? this.DoSomthingHere() 返回什么(签名和“新”声明)?如果有更多信息,我会尝试回答。

标签: class inheritance list compact-framework c#-2.0


【解决方案1】:

我的猜测是 DoSomethingHere 不会返回 MyObjectCollection 的实例。

让我们在这里摆脱所有泛型等,因为它们不相关。以下是我怀疑您正在尝试做的事情:

public static object CreateAnObject()
{
    return new object();
}

object o = CreateAnObject();
string s = (string) o;

这将失败(在执行时),这是正确的。

要将其带回您的代码,除非DoSomethingHere实际上在执行时返回MyObjectCollection,否则转换将失败。

【讨论】:

  • DoSomethingHere()... 或实际情况下的 FindByAssetId(assetTypeId) ,实际情况下返回 List 或 List 。那么,即使是那些 MyObjectCollection 几乎都是 List 我不能用它来投射?看起来它应该可以工作!
  • 不 - 你需要阅读继承概念一些更抱歉
  • 不,您不能将对象转换为其他类型。您可以编写自己的转换器,但这对我来说听起来不是一个好主意。首先 MyObjectCollection 有什么意义?
  • MyObjectCollection 旨在成为使用 List 的一种简洁方式。但是,我将只使用列表或找到其他方法。
  • 如果您要使用速记,您只需要构造 DoSomething 并返回您的专用类而不是泛型。 DoSomething 方法没有使用您的速记类是否有原因?
【解决方案2】:

因为List&lt;MyObject&gt; 不是 MyObjectCollection。反之亦然:您可以将 MyObjectCollection 转换为 List,因为 MyObjectCollection 继承自 List&lt;MyObject&gt;,因此,出于所有意图和目的,IS A List&lt;MyObject&gt;

您唯一能做的就是在 MyObjectCollection 上定义一个构造函数,该构造函数将 Ienumerable 作为参数并使用另一个中的数据初始化自身,但这会生成一个包含相同数据的新对象:

public class MyObjectCollection : List<MyObject> 
{
  public MyObjectCollection(IEnumerable<MyObject> items)
  {
    Addrange(items); 
  }
}

更新: 如评论中所述,只要 DoSomething 实际上返回 MyObjectCollection 的实例,您就可以在运行时成功转换。如果是这样,则该对象实际上是一个 MyObjectCollection,并且强制转换是完全合法的。

我不得不说,在我看来,这样的做法是不好的做法。如果函数返回 List,则不应依赖 List 的特定实现。如果您拥有该函数,则修改 DoSomething 的返回类型并返回 MyObjectCollection,或者将其作为列表处理。

【讨论】:

  • 很想这样做,但是我只能拥有每个类的一个实例,因为它们包含的所有数据都在一个地方进行管理。
  • 您的陈述虽然在一般意义上是正确的(即 List 的每个实例都不是 MyObjectCollection),但不适用于强制转换的每个特定情况。事实上,如果“DoSomething”返回的值是 MyObjectCollection,那么转换将成功,因为基础类型是 MyObjectCollection。
  • 非常正确,史蒂夫。我想我专注于他为什么看到错误。我会更新我的答案,因为它已被投票,不希望出现错误/部分答案。谢谢。
【解决方案3】:

在不知道在 DoSomething() 中究竟创建了什么 的情况下,我们必须假设:

你对.Net中的继承有一个误解。

你有

A : B

B DoSomething() 
{
    return new B();
}
// then this is
B b = new B();
A a = (A)b;

显然 b 是 B 但不是 A。B 可能看起来很像 A 但事实并非如此(如果您遍历 b 的父系,您将在任何地方都找不到 A)

无论所涉及的泛型如何,这都是正确的(尽管有时可能会导致某些情况下,可以工作的东西在 c# 4.0 中看不到共同矛盾的变化)

A : B

B DoSomething() 
{
    return new A();
}
// then this is
B b = new A();
A a = (A)b;

在没有泛型的情况下起作用。

【讨论】:

  • 谢谢你,虽然这不是我选择的答案,但它让我明白了为什么它不起作用。我在乔恩第一次发帖时将他标记为正确。
  • 没关系stackoverflow.com/questions/305223/jon-skeet-facts “用户不会将 Jon Skeet 的答案标记为已接受。宇宙出于真理和正义感而接受他们。” ;)
【解决方案4】:

你不能这样做,因为(我猜)从 DoSomethingHere 返回的列表实例不是从 MyObjectCollection

派生的

【讨论】:

    【解决方案5】:

    您可以创建一个隐式运算符,允许您在对象和列表之间进行转换。你需要一个构造函数,它接受一个列表和返回底层列表的属性。

    public static implicit operator List<MyObject>(MyObjectCollection oCollection)
    {
      //Convert here
      return MyObjectCollection.BaseList;
    }
    
    public static implicit operator MyObjectCollection(List<MyObject> oList)
    {
      //Convert here
      return new MyObjectCollection(oList);
    }
    

    【讨论】:

    • 隐式运算符很糟糕,很糟糕,很糟糕。它们使代码非常难以阅读,可能会引入难以发现的错误,并且对于不是作者的人来说维护起来真的很糟糕。
    • @ctacke - 如果在这种情况下正确使用,那么我看不出没有理由不使用它们。您不会抱怨 int 到双重隐式转换吗?它们在源代码中可见,就像任何其他运算符一样。
    • int to double 保证在所有情况下都可以正常工作而不会丢失数据,通常在默认情况下不使用 bigint/bigrational 的语言中完成......有一个世界不同
    猜你喜欢
    • 2011-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多