【问题标题】:c# implicit conversion from base classc#从基类隐式转换
【发布时间】:2012-06-28 14:34:18
【问题描述】:

我有一个这样的集合类:

public class SomeDataCollection : List<ISomeData>
{
    // some method ...
}

但我不能这样做:

SomeDataCollection someDatas = new List<ISomeData>();

无法隐式将类型List&lt;ISomeData&gt; 转换为SomeDataCollection。存在显式转换(您是否缺少演员表?)

所以我尝试在 SomeDataCollection 集合类中创建一个隐式转换器:

public static implicit operator SomeDataCollection(List<ISomeData> l)
{
    var someDatas = new SomeDataCollection();
    someDatas.AddRange(l);
    return someDatas;
}

但它说我不能创建这样的转换器:

SomeDataCollection.implicit operator SomeDataCollection(List&lt;ISomeData&gt;): 不允许用户定义的与基类之间的转换

当我这样投射时:

SomeDataCollection someDatas = (SomeDataCollection)new List<ISomeData>();

它抛出一个错误说:

System.InvalidCastException: 无法将 List&lt;ISomeData&gt; 类型的对象转换为 SomeDataCollection 类型。

我该怎么做:

SomeDataCollection someDatas = new List<ISomeData>();

没有错误?请帮忙。提前致谢。

【问题讨论】:

标签: c# .net-4.0 implicit-conversion


【解决方案1】:

new List&lt;ISomeData&gt;(); 仍然只是 List&lt;ISomeData&gt;。这不是SomeDataCollection。子类化的重点是子类可以有额外的状态等,但是一个对象(一旦创建)从不改变类型。

不允许在同一层次结构中的类型之间创建运算符,因为这会破坏通常和预期的强制转换行为。

你可以简单地使用:

var data = new SomeDataCollection();

但是我应该坦率地补充一点,将List&lt;T&gt; 子类化很少有用。尤其重要的是,它没有公开任何有用的 virtual 方法,因此您无法调整行为。老实说,我只会使用List&lt;ISomeData&gt;(并完全删除SomeDataCollection),除非我有明确且可证明的目的。然后:我可能封装列表,或者从Collection&lt;T&gt;继承。

您总是可以将方法添加为扩展方法?

public static class Utils {
    public static void SomeMethod(this IList<ISomeData> list) {
      ...
    }
}

然后:

var list = new List<ISomeData>();
...
list.SomeMethod();

【讨论】:

  • 我实际上并没有在SomeDataCollection 中添加一个新实例化的List&lt;ISomeData&gt;,这只是一个示例:P。我使用List&lt;T&gt;,因为它已经有一些添加、删除等对象的功能,而且我的SomeDataCollection 类中还有一些额外的方法和属性,这些方法和属性仅适用于类型List&lt;ISomeData&gt;
  • @John IMO 让某些东西同时成为列表 并且 有自己的状态是错误的;许多框架/库讨厌 - 绑定、序列化、物化等。IMO 你应该有一个对象具有这些属性,并且也具有 一个IList&lt;Foo&gt; Items {get;}
  • 继承 List 通常很有用。一个很好的例子可能是一个可以适应不同条件并为此目的添加属性和方法的列表。然而,即使在这些情况下,T 通常仍然是 T。
  • @ThomasPhaneuf 因为List&lt;T&gt; 没有公开任何多态API,目前还不清楚它可以有效地“适应”任何东西
【解决方案2】:

首先,为什么要将new List&lt;ISomeData&gt;写入定义为SomeDataCollection的变量中? 你可能真的想SomeDataCollection someDatas = new SomeDataCollection();

至于错误信息,第一条错误信息告诉你List&lt;ISomeData&gt;不是从SomeDataCollection派生的,因此你不能用它来做你可以用SomeDataCollection做的事情,所以你不能写它到定义为SomeDataCollection 的变量(想象一下,如果SomeDataCollection 在其中有public void someMethod(),然后在代码中你会调用someDatas.someMethod())。

第二条错误消息告诉您转换器旨在在完全不同的类型之间进行转换,而不是在基于类型和派生类型之间进行转换。否则,你会期望得到什么,例如在以下示例中:

SomeDataCollection a = new SomeDataCollection();
List<ISomeData> b = (List<ISomeData>)a;
SomeDataCollection c = (SomeDataCollection)b;

是否应该调用您的转换器?

基本上,您尝试编写的代码一开始是非常错误的,因此我们需要知道您要做什么,然后也许能够告诉您根本问题的解决方案(而不是问题“如何使这段代码编译”)。

【讨论】:

    【解决方案3】:

    SomeDataCollection中实现构造函数不是更好吗?

    public SomeDataCollection() : base() { }
    

    这当然可以补充

    public SomeDataCollection(IEnumerable<ISomeData> collection) 
        : base(collection) { }
    

    那么你应该可以像这样初始化你的SomeDataCollection

    SomeDataCollection someData = new SomeDataCollection();
    SomeDataCollection someOtherData = 
        new SomeDataCollection(collectionOfSomeData);
    

    并且仍然可以访问List&lt;ISomeData&gt; 中的所有公共方法和属性。

    【讨论】:

      【解决方案4】:

      泛型没有问题。在 C# 中,不允许将基类显式转换为派生类。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多