c# 从基类的隐式转换

问题描述 投票:0回答:5

我有一个像这样的集合类:

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

但我不能这样做:

SomeDataCollection someDatas = new List<ISomeData>();

无法隐式将类型

List<ISomeData>
转换为
SomeDataCollection
。存在显式转换(您是否缺少转换?)

所以我尝试在

SomeDataCollection
集合类中创建一个隐式转换程序:

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

但它说我无法创建这样的转换器:

SomeDataCollection.implicit operator SomeDataCollection(List<ISomeData>)
不允许与基类进行用户定义的转换

当我像这样投射它时:

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

它抛出一个错误:

System.InvalidCastException: 无法将

List<ISomeData>
类型的对象强制转换为
SomeDataCollection
类型。

我该怎么做:

SomeDataCollection someDatas = new List<ISomeData>();

没有出现错误?请帮忙。预先感谢。

c# .net-4.0 implicit-conversion
5个回答
6
投票

A

new List<ISomeData>();
仍然只是
List<ISomeData>
。这不是
SomeDataCollection
。子类化的要点是子类可以有额外的状态等,但是对象(一旦创建)永远不会改变类型。

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

您可以简单地使用:

var data = new SomeDataCollection();

但是我应该补充一点,坦率地说,子类化

List<T>
很少有用。最重要的是,它没有公开任何有用的
virtual
方法,因此您无法调整行为。老实说,我只会使用
List<ISomeData>
(并完全删除
SomeDataCollection
),除非我有明确且可证明的目的。然后:我可能会封装列表,或者继承
Collection<T>

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

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

然后:

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

2
投票

首先,为什么要将

new List<ISomeData>
写入定义为
SomeDataCollection
的变量中? 有可能你真的想要
SomeDataCollection someDatas = new SomeDataCollection();

至于错误消息,第一条错误消息告诉您

List<ISomeData>
不是从
SomeDataCollection
派生的,因此您不能用它做一些您可以用
SomeDataCollection
做的事情,因此您不能将它写入定义为
SomeDataCollection
的变量(想象一下,如果
SomeDataCollection
中有
public void someMethod()
,稍后在代码中您将调用
someDatas.someMethod()
)。

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

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

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

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


2
投票

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

public SomeDataCollection() : base() { }

这当然可以补充

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

然后你应该能够像这样初始化你的

SomeDataCollection

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

并且仍然可以访问

List<ISomeData>
中的所有公共方法和属性。


0
投票

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


0
投票

我只是无法理解为什么存在从类类型到其任何基类类型的隐式转换。

例如,C# 文档中提供了一个示例...

要有一些课堂要点

public Point
{
  int X;
  int Y;

  point (int x, int y)
  {
    X = x;
    Y = y;
  }

}


Now u declare some class Point3D inherited from Point class

public class Point3D:Point
{
   int Z;

   Point3D (int x, int y, int z) : base (x, y)
   {
      Z = z;
   }

}

现在您可以将某些代码中的某些点声明为...

Point a = new(10, 20);
Point b = new Point3D(10, 20, 30);

这一切是不是造成了一些混乱?我的意思是这里类型安全的含义是什么?实际上,3D 点和 2D 点不是不同的实体吗?不是吗?并且相同类型的 Point 变量可以引用 Point3D 类型对象。

你可以做任何事,没有问题。毕竟,它只是下面的一个指针。所以基本上所有类型的指针或引用在机器上的大小都相同。那么为什么不将任意类型的指针转换为任意类型呢?引用是引用类型或指针......它可以保存任何引用类型。为什么只停留在继承的类基类场景中?

如果你允许这样的事情,那么有人可能会为该代码的未来维护者创建令人困惑的代码,不是吗?

我对所有这些编程都是新手,所以不太了解。所以如果从你的角度来看这是愚蠢的,请原谅我,但我想清除我心中的这种困惑。

© www.soinside.com 2019 - 2024. All rights reserved.