【问题标题】:Why can't I override and new a Property (C#) at the same time?为什么我不能同时覆盖和新建一个属性 (C#)?
【发布时间】:2010-03-23 23:01:55
【问题描述】:

根据 this question 看来,您可以为方法执行此操作。我想知道的是为什么当我用属性尝试它时它不起作用。

public class Foo
{
    public virtual object Value
    {
        get;
        set;
    }
}

public class Foo<T> : Foo
{
    public override object Value
    {
        get
        {
            return base.Value;
        }
        set
        {
            base.Value = (T)value; //inject type-checking on sets
        }
    }

    public new T Value
    {
        get { return (T)base.Value; }
        set { base.Value = value; }
    }
}

来自 C# 4.0 RC1 的错误消息

错误 1 ​​类型 'ClassLibrary1.Foo' 已经 包含“价值”的定义 ClassLibrary1\Class1.cs 31 22 类库1

【问题讨论】:

    标签: c# .net inheritance methods


    【解决方案1】:

    您不能有两个属性使用相同的名称。这在 C# 中是不允许的。唯一的例外是索引器,因为在索引器的情况下,签名会随索引类型而变化。

    您不能对仅因返回类型不同的方法进行重载。同一个规则基本上禁止具有单一名称的属性,因为它在内部是一对没有用于 get 访问器参数的方法。

    【讨论】:

    【解决方案2】:

    如果您执行以下操作,则可以执行此操作...

    public interface IFoo<T>
    {
        T Value { get; set; }
    }
    
    public class Foo<T> : Foo, IFoo<T>
    {
        T IFoo.Value
        {
            get { return (T)base.Value; }
            set { base.Value = value; }
        }
    }
    

    唯一的一点是,当您引用时,您必须使用接口类型......即

       IFoo<int> myfoo = new Foo<int>();
       int result = myFoo.Value;    //This will give you the typed version
    
       Foo<int> myfoo = new Foo<int>();
       int result = myFoo.Value;    //This will give throw an exception
    

    【讨论】:

    • 事实上,我不得不想出一个稍微不同的解决方法,因为我的基类不是抽象的,它真的应该与对象一起使用(它只会在你使用类型构造它时停止使用对象参数)。
    【解决方案3】:

    即使 C# 做不到,C++/CLI 也能做到。在 C++/CLI 中,您可以明确说明要覆盖哪个方法,因此名称不必匹配。

    【讨论】:

      【解决方案4】:

      您可以通过交互来解决此问题。

      public interface IFoo
      {
          object Value { get; set; }
      }
      
      public class Foo<T> : IFoo
      {
          object _value = null;
          object IFoo.Value
          {
              get { return _value; }
              set { _value = value; }
          }
      
          public T Value
          {
              get;
              set;
          }
      }
      

      【讨论】:

        【解决方案5】:

        根本问题是永远无法知道要使用哪个属性。

        例如,

        Foo<int> s = new Foo<int>();
        
        s.Value = "hmmm";
        

        那么应该使用哪个属性呢? int 派生自 object 并且也满足通用属性版本的约束。

        【讨论】:

        • 我的意图是那会抛出(如果你能让它编译:-))
        • 一点也不含糊。被覆盖的虚拟属性将用于通过基类引用进行多态访问,新属性将用于通过派生类(或其任何后代)静态类型化的引用进行访问。实现这一点的一种方法是使用中间基类来提供覆盖定义。
        【解决方案6】:

        同一属性Value 有两个定义,一个由 override ... 定义,一个由 new 定义。返回类型不是方法签名中的区别特征,即如果签名仅在返回类型上不同,则签名被认为是相同的。因此,请使用 override 或 new。

        在您的情况下,您可以使用 new 而不是 override 来实现目标。但是,在使用 new 时,您始终必须考虑执行的实现取决于您调用该方法的类型。即

        var foo = new Foo();
        var foo_ = new Foo<string>();
        
        foo.Value            // calls the implementation on Foo 
        foo_.Value           // calls the implementation on Foo<T>
        ((Foo) foo).Value    // calls the implementation on Foo
        

        【讨论】:

        • 是的,这正是我想要的行为。我想要的有趣的是: ((Foo) foo_).Value // 调用 Foo 上的实现
        • 严格来说,覆盖不需要名称。它只需要某种方法与正确的 v-table 插槽相关联。不幸的是,C# 只使用名称进行关联(C++/CLI,我相信 MSIL 也有办法显式建立关联)。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-29
        • 1970-01-01
        • 2011-09-14
        • 1970-01-01
        • 2020-11-06
        相关资源
        最近更新 更多