C#子类中的受保护属性是否应隐藏对父级公共属性的访问权限?

Tim*_*tin 29 c# mono

我有以下代码:

public class Parent
{
    public string MyField { get; set; }
}

public class Child : Parent
{
    protected new int MyField { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我试着通过以下方式访问:

static void Main(string[] args)
{
    Child child = new Child();
    child.MyField = "something";
}
Run Code Online (Sandbox Code Playgroud)

Visual Studio 2008编译时没有注释,但在Mono(2.4.2,Ubuntu)下我收到错误消息

'HideTest.Child.MyField' is inaccessible due to its protection level (CS0122)
Run Code Online (Sandbox Code Playgroud)

一个实现或其他更符合标准吗?

编辑:感谢所有指出糟糕设计的人.不幸的是,它是第三方库,并且显着地改变它是不实际的.

Jas*_*yon 25

来自ECMA-334(C#规范)§10.7.1.2:

新成员的声明仅在新成员的范围内隐藏继承的成员.

您可以通过在Microsoft的实现上运行此测试来查看此行为.

using System;
using NUnit.Framework;

namespace ScratchPad
{
    [TestFixture]
    public class Class1
    {
        [Test]
        public void InheritanceHiding()
        {
            var b = new Base();
            var d = new Derived();

            var baseSomeProperty = b.SomeProperty;
            var derivedSomeProperty = d.SomeProperty;

            b.GetSomeProperty();
            d.GetSomeProperty();
        }
    }

    public class Base
    {
        public string SomeProperty
        {
            get
            {
                Console.WriteLine("Getting Base.SomeProperty");
                return "Base.SomeProperty";
            }
        }

        public string GetSomeProperty()
        {
            return SomeProperty;
        }
    }

    public class Derived : Base
    {
        protected new int SomeProperty
        {
            get
            {
                Console.WriteLine("Getting Derived.SomeProperty");
                return 3; //Determined by random roll of the dice.
            }
        }

        public new int GetSomeProperty()
        {
            return SomeProperty;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

哪个会输出:

Getting Base.SomeProperty    //(No Controversy)  
Getting Base.SomeProperty    //(Because you're calling from public scope and the new member is in protected scope, there is no hiding)  
Getting Base.SomeProperty    //(No Controversy)  
Getting Derived.SomeProperty //(Now because you're calling from protected scope, you get the protected member).
Run Code Online (Sandbox Code Playgroud)

因此,您从中访问的属性Main()应该是基类属性(在MS.NET中),而不是派生属性(如在Mono中),因为新派生成员仅隐藏受保护的"旧"基本成员范围.

根据规范,Mono在这里做错了.


Eri*_*ert 18

杰森的回答是正确的,但他要求对这种行为进行辩解.(即隐藏方法仅隐藏在隐藏方法的范围内.)

有许多可能的理由.特别值得一提的是,这是C#设计减轻脆性基类问题的另一种方式.

FooCorp制作Foo.DLL:

public class Foo
{
    public object Blah() { ... }
}
Run Code Online (Sandbox Code Playgroud)

BarCorp制作Bar.DLL:

public class Bar : Foo
{
    // stuff not having to do with Blah
}
Run Code Online (Sandbox Code Playgroud)

ABCCorp制作ABC.EXE:

public class ABC
{
    static void Main()
    {
        Console.WriteLine((new Bar()).Blah());
    }
}
Run Code Online (Sandbox Code Playgroud)

现在BarCorp说:"你知道,在我们的内部代码中,我们可以保证Blah只返回字符串,这要归功于我们对派生实现的了解.让我们在内部代码中利用这个事实."

public class Bar : Foo
{
    internal new string Blah()
    {
        object r = base.Blah();
        Debug.Assert(r is string);
        return (string)r;
    }
}
Run Code Online (Sandbox Code Playgroud)

ABCCorp选择了一个新版本的Bar.DLL,它有一些阻止它们的bug修复.他们的构建是否应该打破,因为他们调用了Blah,Bar上的内部方法?当然不是.那太可怕了.此更改是一个私有实现细节,应该在Bar.DLL之外不可见.

  • 你知道你有一个美好的一天,Eric Lippert告诉你你是对的.谢谢你回答蝙蝠信号:) (15认同)

Jam*_*ack 5

一般来说,C#的.NET实现应该被认为是"佳能".从新修改器的文档:

类或结构中引入的常量,字段,属性或类型会隐藏具有相同名称的所有基类成员.

......根据这个定义,似乎Mono实现更正确.它应该隐藏MyFieldParent类中的实现,因此只能使用类中的int MyField签名访问它Child.