代码之家  ›  专栏  ›  技术社区  ›  Luis Filipe

我可以用派生类型重写吗?

  •  36
  • Luis Filipe  · 技术社区  · 16 年前

    据我所知,不可能在C 2.0中执行以下操作

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

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

    public new Child SomePropertyName
    

    2.0中有什么解决方案吗? 3.5中解决这个问题的功能是什么?

    8 回复  |  直到 7 年前
        1
  •  22
  •   Neuron MonoThreaded    7 年前

    这在任何.NET语言中都不可能,因为存在类型安全问题。在类型安全语言中,必须为返回值提供协方差,为参数提供协方差。采用此代码:

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

    对于 Get 方法,协方差意味着 T 要么是 S 或派生自 S . 否则,如果您引用了类型为的对象 D 存储在类型化变量中 B ,当你打电话时 B.Get() 你不会得到一个可以表示为 S 后退——破坏类型系统。

    对于 Set 方法,逆变意味着 T 要么是 S 或那种类型 S 源于否则,如果您引用了类型为的对象 D 存储在类型化变量中 ,当你打电话时 B.Set(X) 在哪里 X 属于类型 S 但不是类型 T , D::Set(T) 将得到一个它不期望的类型的对象。

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

        2
  •  40
  •   Marc Gravell    16 年前

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

    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
        }
    }
    
        3
  •  11
  •   Keith    16 年前

    不,但您可以在2和更高版本中使用泛型:

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

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

        4
  •  7
  •   dalle    16 年前

    Wikipedia :

    在C编程语言中,支持两种返回类型 协方差和参数 增加了代表的反差 语言版本2.0。 既不协方差也不协方差 方法重写支持。

    但它并没有明确地说明属性的协方差。

        5
  •  2
  •   VVS    16 年前

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

        6
  •  1
  •   Anthony Waqas Raja    16 年前

    不,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();
            }
        }
    }
    

    即使用由基类定义的协定,但返回派生类型。我做了一个更详细的样本来说明这一点——再次返回“this”不会改变任何东西。

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

    基类虚拟方法(在本例中是虚拟属性)不仅有一个实现,而且还定义了一个约定:如果子类满足此约定,则它可以提供somepropertyname的不同实现(即somepropertyname返回“fatherprop”类型的对象)。返回从“fatherprop”派生的“childprop”类型的对象符合此合同。但是你不能在“child”中更改契约——这个契约适用于所有从“father”派生的类。

    如果您退后一步,看看您的更广泛的设计,在C工具箱中还有其他语言结构,您可能还需要考虑它们——泛型或接口。

        7
  •  1
  •   Micah    16 年前

    不,C不支持这个想法 (这叫做“返回类型 协方差“”。

    维基百科:

    在C编程语言中, 两种返回类型的支持 协方差和参数 增加了代表的反差 语言版本2.0。 既不协方差也不协方差 方法重写支持。

    你可以重新申报(新的),但是你 无法在处重新声明和重写 同一时间(同名)。一 选项是使用受保护的方法 隐藏细节-这允许 多态性和隐藏性 时间:

    最好的解决方案是使用仿制药:

    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
    
        8
  •  0
  •   Mark Cidade    16 年前

    这是我能做到的最接近的(到目前为止):

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

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