繁体   English   中英

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

[英]Why can't I write an implicit operator from a Base class to a Derived class in C#?

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);
    }
}

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

编辑:更改了问题的标题

因为已经有从DerivedBaseClass的隐式转换,并且反过来没有任何意义。

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

标准的强制性引用:

6.1.6隐式引用转换

隐式引用转换是:

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

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

6.2.4显式引用转换

显式引用转换是:

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

这表示已经有一个显式转换Base => Derived (这是允许你在运行时尝试向下转换的原因)。

6.4.1允许的用户定义转换

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

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

因为它会扰乱多态性的系统。

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

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

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

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

baseClass = (BaseClass)derived;

但是你无法将Derived重写为BaseClass。

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

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

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

class AnnotatedAlert : Alert
{
    public string Color;

    // I don't know why C# doesn't allow user defined conversions from a base class
    // so I am creating a conversion constructor instead
    public AnnotatedAlert(Alert from)
    {
        AutoMapper.Mapper.Map(from, this);
    }

    static AnnotatedAlert()
    {
        AutoMapper.Mapper.CreateMap<Alert, AnnotatedAlert>();
    }
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM