【问题标题】:How do you deal with overriding functions with different type results?您如何处理具有不同类型结果的覆盖函数?
【发布时间】:2011-09-02 08:25:44
【问题描述】:

这个问题最明显的例子是函数克隆(只是一个EXAMPLE家伙)。假设您有 BaseClass 和 DerivedClass ——除非我错过了什么,否则在两个函数(每个类的克隆)中,您分别创建 BaseClass 和 DerivedClass 但实际上返回了对象。 如果您想使用“真实”类,这就是问题所在。

到目前为止,我只看到两个解决此问题的方法:

1.每次将函数的结果转换为适当的类

var real_stuff = (RealStuff)x.Clone(); // I want real stuff

2. 提供第二个功能,因此您将拥有 Clone(如果您在基类级别工作)和 CloneThis(如果您想在给定班级工作,结果会因班级而异等级)

   public override object Clone()
    {
       return CloneThis();
    }
    public RealStuff CloneThis()
    {
       return new RealStuff(this);
    }

第一个很丑,第二个很烦。

问题:您如何处理这个问题?

另外一件事——如果你愿意,也请评论一下——为什么在重写函数签名检查时如此严格?除了“因为它是这样设计的”或 Eric Lippert 最喜欢的“因为每个功能都需要......”;-) 我认为允许覆盖具有更改结果类型的函数没有技术(和逻辑等)问题 IF 被覆盖的函数结果派生自原始函数结果类型。

例子:

  class ClassA
  {
    public virtual ClassA GetIt() ...
  }

  class ClassB : ClassA
  {
    public override ClassB GetIt() ...
  }

目前它不是正确的代码,但我认为它在技术上可能是,因为 ClassB 是从 ClassA 派生的。无论您对输出做什么,“接收者”都需要 ClassA,所以 ClassB 满足这个要求。

所以你可以写:

  ClassA class_a_b = new ClassB();
  ClassB class_b_b = new ClassB();

  ClassA result1 = class_b_b.GetIt();
  ClassA result2 = class_a_b.GetIt();
  ClassB result3 = class_b_b.GetIt();
  // incorrect, derived GetIt would be called OK, 
  // but the signature is taken from ClassA
  ClassB result4 = class_a_b.GetIt(); 

我也不认为拥有这样的能力任何人都会对这种行为感到惊讶,恕我直言,这是一致的。

请保持您的回答符合主题,“您不应该使用 ICloneable” 符合主题。谢谢。

【问题讨论】:

  • 您是否考虑过一个公共虚拟 T Clone 方法,该方法可以被覆盖并在没有推断出的类型的情况下调用 Clone(myObj) ?
  • @Paolo Tedesco,第二个很好,谢谢。这个问题是DUPLICATE,我该如何关闭它?
  • @macias:我还是回答了,即使我认为这在某种程度上是重复的,因为我想添加一些东西(关于转换为基本接口和隐式转换运算符)。但是,我认为您不能关闭自己的问题(人们必须投票才能关闭)。
  • 我相信你可以删除自己的问题,当然我已经按照一些链接找到“作者自愿删除了这个问题”或类似的内容。

标签: c# polymorphism overriding


【解决方案1】:

检查这两个问题:

基本上,处理这个问题的方法是定义一个具有适当返回类型的通用接口,例如

interface ICloneable<T> {
    T Clone();
}

但是,这不允许您将接口用作基本类型,因为 ICloneable 和 ICloneable 是两个不同的东西。

只有返回类型不同的函数是“技术上可能的”,事实上 CLR 允许这样做,但 C# 不允许,可能是因为不可能总是猜测要调用的正确重载。 (实际上在 C# 中,您可以使用隐式强制转换运算符来做到这一点:它们被编译为名称为 op_Implicit 和不同返回类型的函数。

【讨论】:

  • 第二个链接太棒了,我已经看过了,不仅接受的答案很好,其他答案也很好。我注意到至少有 4 种可靠的(!)方法。当然,开箱即用地拥有这样的能力会更好。只需评论您的陈述“不可能总是猜测正确的重载调用。”它不是重载,它是覆盖(我询问过覆盖),并且总是知道要调用哪个函数,即编译时类级别的那个。
猜你喜欢
  • 1970-01-01
  • 2012-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-27
  • 2021-10-16
  • 1970-01-01
相关资源
最近更新 更多