为什么我不能将一个隐式运算符从Base类写入C#中的Derived类?

时间:2012-06-01 15:27:36

标签: c# operators

public class Derived : BaseClass
{
    public Derived(string name) : base(name) {}

    public static implicit operator BaseClass(Derived derived)
    {
        return new BaseClass(derived.ColorHex);
    }

    public static implicit operator Derived(BaseClass baseclass)
    {
        return new Derived(baseclass.name);
    }
}

这不起作用。为什么不允许?
可以潜在地写出有必要的逻辑,特别是在从基础转换为派生的逻辑时。

编辑:更改了问题的标题

5 个答案:

答案 0 :(得分:8)

因为已经存在从DerivedBaseClass的隐式转换,反之亦然。

关于后者:如果您的Base对象可以隐式转换为Derived - 为什么它们首先不是Derived个对象?

standard

的强制引用
  

6.1.6隐式参考转换

     

隐式参考转换是:

     
      
  • [...]
  •   
  • 从任何类型S到任何类型类型T,只要S是   源自T。
  •   

这表示存在隐式转化Derived => Base,我们都知道。

  

6.2.4显式参考转换

     

显式引用转换为:

     
      
  • [...]
  •   
  • 从任何类型S到任何类型类型T,只要S是T的基类。
  •   
  • [...]
  •   

这表示已经有明确的转化Base => Derived(允许您在运行时尝试向下转换)。

  

6.4.1允许的用户定义转换

     

C#仅允许声明某些用户定义的转换。的在   特别是,不可能重新定义已经存在的   隐式或显式转换。

这说明由于两种兴趣转换已经由语言定义,因此您无法重新定义它们。

答案 1 :(得分:1)

因为它会扰乱多态性的结合。

答案 2 :(得分:1)

一般规则是将对象转换为自己的类型的结果是原始对象。如果类型BaseType的存储位置包含DerivedType的实例,则从原始类型转换为DerivedType应该告诉编译器使用DerivedType的成员,但是不应该实际上对对象“做”任何事情。如果允许自定义的从基础到派生的转换运算符,则有必要:(1)具有转换为实例的自有类型操作有时会产生新对象,有时不产生,或者(2)具有派生类型存储在基本类型存储位置中的对象与基本类型或不相关类型的对象的行为基本不同,没有明确可见的类型检查代码,这将使其这样做。虽然有时候人们可能想要一个方法,给定一个base-type参数,可能会返回一个新的派生类型对象,或者 - 如果给定一个派生类型的实例,只需返回它未经修改,通常更好的方法是有这样的东西“看起来”像一个方法而不是类型转换。

BTW,有一种情况是编译器可以在“基本类型”和“派生类型”之间允许用户定义的类型转换而没有上述歧义:当其中一个类型是结构时。虽然C#假装值类型继承自ValueType,但每个值类型定义确实定义了两件事:一个派生自ValueType的堆对象类型,以及一个不是对象的存储位置集合。不是来自任何东西。 C#定义了从后一种类型到前者的隐式转换运算符,以及从前者到后者的显式转换运算符。由于堆对象和存储位置集合之间的转换永远不会引用保留,因此允许在此类上下文中使用用户定义的转换运算符不会导致混乱的继承语义。这种转换的唯一困难是使用它们的值类型要么作为泛型类型不可用,要么如果作为泛型类型传递则会丢失它们的特殊行为。

答案 3 :(得分:0)

要合成,您可以将Derived对象转换为BaseClass对象,而无需编写任何代码:

BaseClass baseClass = new BaseClass("");
Derived derived = new Derived("");

baseClass = (BaseClass)derived;

但你无法将Derived中的强制转换重写为BaseClass。

对于其他演员,从BaseClass到Derived,它没那么有意义。

总之,只有在两个类之间没有继承关系时,才能重新定义强制转换。

答案 4 :(得分:0)

我需要能够从基础对象创建派生对象,以便捕获基类没有的其他信息。出于我的目的,构造一个派生对象,其中包含从基础对象复制的所有字段。我使用AutoMapper让我的生活更轻松:

String prefix = "ignore(FAILURE) { build(\"load\", ";
String ending = "}}";
for (String first: arr_1) {
    for (String second: arr_2) {
       System.out.println( prefix + first + second + ending);
    }
    for (String second: arr_3) {
       System.out.println( prefix + first + second + ending);
    }
    for (String second: arr_4) {
       System.out.println( prefix + first + second + ending);
    }
}