C# 我可以使用派生类型覆盖吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/157119/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 16:03:43  来源:igfitidea点击:

Can I Override with derived types?

提问by Luis Filipe

As far as i know it is not possible to do the following in C# 2.0

据我所知,在 C# 2.0 中无法执行以下操作

public class Father
{
    public virtual Father SomePropertyName
    {
        get
        {
            return this;
        }
    }
}

public class Child : Father
{
    public override Child SomePropertyName
    {
        get
        {
            return this;
        }
    }
}

I workaround the problem by creating the property in the derived class as "new", but of course that is not polymorphic.

我通过在派生类中将属性创建为“new”来解决这个问题,但这当然不是多态的。

public new Child SomePropertyName

Is there any solution in 2.0? What about any features in 3.5 that address this matter?

2.0有什么解决方案吗?3.5 中解决此问题的任何功能怎么样?

采纳答案by Alex Lyman

This is not possible in any .NET language because of type-safety concerns. In type-safe languages, you must provide covariance for return values, and contravariance for parameters. Take this code:

由于类型安全问题,这在任何 .NET 语言中都是不可能的。在类型安全的语言中,您必须为返回值提供协方差,并为参数提供逆变。拿这个代码:

class B {
    S Get();
    Set(S);
}
class D : B {
    T Get();
    Set(T);
}

For the Getmethods, covariance means that Tmust either be Sor a type derived from S. Otherwise, if you had a reference to an object of type Dstored in a variable typed B, when you called B.Get()you wouldn't get an object representable as an Sback -- breaking the type system.

对于Get方法,协方差意味着T必须是S或从 派生的类型S。否则,如果您有一个对D存储在变量 typed 中的类型对象的引用B,当您调用时,B.Get()您将不会得到一个可表示为Sback的对象——破坏了类型系统。

For the Setmethods, contravariance means that Tmust either be Sor a type that Sderives from. Otherwise, if you had a reference to an object of type Dstored in a variable typed B, when you called B.Set(X), where Xwas of type Sbut not of type T, D::Set(T)would get an object of a type it did not expect.

对于Set方法,逆变意味着T必须是SS派生自的类型。否则,如果您有一个对D存储在 typed 变量中的类型对象的引用B,当您调用时B.Set(X), whereX是 typeS但不是 type TD::Set(T)会得到一个它不期望的类型的对象。

In C#, there was a conscious decision to disallow changing the type when overloading properties, even when they have only one of the getter/setter pair, because it would otherwise have very inconsistent behavior ("You mean, I can change the type on the one with a getter, but not one with both a getter and setter? Why not?!?"-- Anonymous Alternate Universe Newbie).

在 C# 中,有意识地决定不允许在重载属性时更改类型,即使它们只有一个 getter/setter 对,因为否则它会产生非常不一致的行为(“你的意思是,我可以在一个有 getter,但不是一个同时有 getter 和 setter 的?为什么不呢?!?”——匿名备用宇宙新手)。

回答by Anthony

No. C# does not support this idea (it's called "return type covariance"). You can however do this:

不。C# 不支持这个想法(它被称为“返回类型协方差”)。但是,您可以这样做:

public class FatherProp
{
}

public class ChildProp: FatherProp
{
}


public class Father
{
    public virtual FatherProp SomePropertyName
    {
        get
        {
            return new FatherProp();
        }
    }
}


public class Child : Father
{
    public override FatherProp SomePropertyName
    {
        get
        {
            // override to return a derived type instead
            return new ChildProp();
        }
    }
}

i.e. use the contract defined by the base class, but return a derived type. I have made a more detailed sample to make this point clearer - returning "this" again wouldn't change anything.

即使用基类定义的契约,但返回派生类型。我制作了一个更详细的示例以更清楚地说明这一点 - 再次返回“this”不会改变任何内容。

It is possible (but messy) to test the returned object for it's actual type (i.e. "if someObject is ChildProp"), but it is better to call a virtual method on it that does the right thing for its type.

可以(但很麻烦)测试返回的对象的实际类型(即“如果 someObject 是 ChildProp”),但最好在其上调用对其类型执行正确操作的虚拟方法。

The base class virtual method (in this case, virtual property) not only has an implementation, but also defines a contract: that a child class can supply a different implementation of SomePropertyName if it meets this contract (i.e. SomePropertyName returns an object of type "FatherProp"). Returning an object of type "ChildProp" derived from "FatherProp" meets this contract. But you can't change the contract in "Child" - this contract applies to all classes descended from "Father".

基类虚方法(在本例中为虚拟属性)不仅有一个实现,而且还定义了一个约定:如果满足这个约定,子类可以提供 SomePropertyName 的不同实现(即 SomePropertyName 返回类型为“的对象”)父亲道具”)。返回一个从“FatherProp”派生的“ChildProp”类型的对象符合这个约定。但是你不能改变“Child”中的契约——这个契约适用于“Father”的所有后代。

If you take a step back and look at your broader design, there are other language constructs in the C# toolkit that you may also want to think about instead - Generics, or interfaces.

如果您退后一步查看更广泛的设计,您可能还想考虑 C# 工具包中的其他语言结构 - 泛型或接口。

回答by Marc Gravell

You can re-declare (new), but you can't re-declare and override at the same time (with the same name). One option is to use a protected method to hide the detail - this allows both polymorphism and hiding at the same time:

可以重新声明(new),但不能同时重新声明和覆盖(同名)。一种选择是使用受保护的方法来隐藏细节 - 这允许同时进行多态和隐藏:

public class Father
{
    public Father SomePropertyName
    {
        get {
            return SomePropertyImpl();
        }
    }
    protected virtual Father SomePropertyImpl()
    {
        // base-class version
    }
}

public class Child : Father
{
    public new Child SomePropertyName
    {
        get
        { // since we know our local SomePropertyImpl actually returns a Child
            return (Child)SomePropertyImpl();
        }
    }
    protected override Father SomePropertyImpl()
    {
        // do something different, might return a Child
        // but typed as Father for the return
    }
}

回答by dalle

From Wikipedia:

来自维基百科

In the C# programming language, support for both return-type covariance and parameter contravariance for delegates was added in version 2.0 of the language. Neither covariance nor contravariance are supported for method overriding.

在 C# 编程语言中,该语言的 2.0 版中添加了对委托的返回类型协变和参数逆变的支持。方法覆盖既不支持协方差也不支持逆变。

It doesn't explicitly say anything about covariance of properties though.

虽然它没有明确说明属性的协方差。

回答by Keith

No, but you can use generics in 2 and above:

不,但您可以在 2 及以上使用泛型:

public class MyClass<T> where T: Person
{
    public virtual T SomePropertyName
    {
        get
        {
            return  ...;
        }
    }
}

Then Father and Child are generic versions of the same class

那么父亲和孩子是同一个类的通用版本

回答by VVS

You can create a common interface for father and child and return a type of that interface.

您可以为父亲和孩子创建一个公共接口并返回该接口的类型。

回答by Micah

No. C# does not support this idea (it's called "return type covariance").

From Wikipedia:

In the C# programming language, support for both return-type covariance and parameter contravariance for delegates was added in version 2.0 of the language. Neither covariance nor contravariance are supported for method overriding.

You can re-declare (new), but you can't re-declare and override at the same time (with the same name). One option is to use a protected method to hide the detail - this allows both polymorphism and hiding at the same time:

不。C# 不支持这个想法(它被称为“返回类型协方差”)。

来自维基百科:

在 C# 编程语言中,该语言的 2.0 版中添加了对委托的返回类型协变和参数逆变的支持。方法覆盖既不支持协方差也不支持逆变。

可以重新声明(new),但不能同时重新声明和覆盖(同名)。一种选择是使用受保护的方法来隐藏细节 - 这允许同时进行多态和隐藏:

The best solutions would be to use generics:

最好的解决方案是使用泛型:

public class MyClass<T> where T: Person
{
   public virtual T SomePropertyNameA
   {        
      get { return  ...; }    
   }
}//Then the Father and Child are generic versions of the same class

回答by Mark Cidade

This is the closest I could come (so far):

这是我能来的最近的一次(到目前为止):

    public sealed class JustFather : Father<JustFather> {}

    public class Father<T> where T : Father<T>
    { public virtual T SomePropertyName
        { get { return (T) this; }
        }
    }

    public class Child : Father<Child>
    { public override Child SomePropertyName
        { get { return  this; }
        }
    }

Without the JustFatherclass, you couldn't instantiate a Father<T>unless it was some other derived type.

没有JustFather该类,Father<T>除非它是其他派生类型,否则您无法实例化 a 。