为什么我使用“protected”关键字无效?

4

我读过受保护的成员可以从派生类中访问,但以下代码不起作用。

class A
{
    protected int Test;
}
class B:A
{
    A instanceOfA= new A()

    public B()
    {
        instanceOfA.Test //Not possible
    }
}

请查看这个答案 - https://dev59.com/NnI-5IYBdhLWcg3weoPR#1836932 - yellowblood
7个回答

25

我已经阅读了受保护成员可以从派生类中访问的内容。为什么我的“protected”使用不起作用?

这是非法的,因为您没有提供访问“B”实例数据的保证。考虑类似的情况:

abstract class BankAccount
{
    protected int accountNumber;
}
class SwissBankAccount : BankAccount
{
}
--- in another assembly, evil-doers write ---
class EvilBankAccount : BankAccount
{
    void DoEvil()
    {
        BankAccount b = GetASwissBankAccount();
        int number = b.accountNumber;
    }
}

EvilBankAccount不继承自SwissBankAccount,因此EvilBankAccount内部不允许使用SwissBankAccount的受保护成员。您可以访问“父类”的受保护成员,但不能访问“兄弟类”的受保护成员!EvilBankAccount只能访问EvilBankAccount(或从EvilBankAccount派生的类型)的受保护成员。SwissBankAccount的受保护成员是禁止访问的。
规则是:访问受保护实例成员的“接收器”表达式的类型必须至少与包含成员访问的类型声明一样派生。有关规则的精确措辞和一些说明性示例,请参见C# 4.0规范的第3.5.3节。
顺便提一下,C++也有这个规则。

这个规则经常被误解。想要更深入地了解这个规则以及protected访问修饰符的其他后果,请参阅我关于此主题的文章。我写过的与此主题最相关的文章是这篇这篇。我还写了一堆关于相关主题的文章在这里(尽管其中一些偏离了protected访问本身的主题,而是涉及如何使用protected访问修饰符构建具有父引用的数据模型)。


9
@FreeAsInBeer: 嗯,您有权发表专业意见。我认为您的回答实际上并没有回答问题。与其像我那样回答“为什么使用 protected 不起作用?”,您选择说“你做错了”,却从未解释 C# 的哪个规则导致了错误。这是我经常遇到的问题;它是语言设计和类型安全性的一个微妙点。 - Eric Lippert
5
@FreeAsInBeer:你知道Eric Lippert是谁吧? - marc_s
9
虽然我理解你的观点,但有趣的是,当我第一次回答关于编程语言设计的问题时,这位年级比我小的人试图教育我。请记住,StackOverflow 是一个社区系统。答案的正确性和实用性是由社区评判的,而不是基于回答者所谓的资质。如果 Beer 小少爷认为我的答案没什么用,他当然有权发表自己的意见,我们不应该否认他这个权利。 - Eric Lippert
既然还没有其他人,我就点赞了这个答案。 是的,它比提问者预期的要复杂一些,但那是因为她提出了一个比自己理解的还要复杂的问题。值得读几遍,直到你明白为止。当然,有其他更简单的答案也很好。这就是为什么允许多人发表答案的原因。 - Cody Gray
1
@Eric Lippert:当然 - SO(Stack Overflow)社区也非常棒!我只是猜测,作为微软C#设计团队的一员,您可能比其他大多数程序员更深入了解C#中某些东西的内部工作原理 :-) - marc_s
7
@FreeAsInBeer: 我的真诚建议是深呼吸,不要过于情绪化。这是一个社区网站,我们都在这里相互帮助,通过解决技术问题来学习。编程很难,语言很复杂,讽刺不会对任何人有所帮助。 - Eric Lippert

3

您的代码设置不正确。类 B 不应该有一个类 A 的实例。相反,类 B 本身继承了类 A 的受保护变量。

您的代码应该更像这样:

class A
{
   protected int Test;
}
class B:A
{
   public B()
   {
       int someInt = this.Test;
   }
}

+1 补充一下 - 你可以从派生类的实例中访问基类的受保护成员 - 更多细节请参见此链接 http://msdn.microsoft.com/en-us/library/bcd5672a%28v=VS.71%29.aspx - tom502
问题在于我原本以为可以访问基类实例的受保护成员,所以我尝试在派生类中创建了一个基类实例。 - Miria
1
@SolutionYogi - 在 OP 的代码中,B 也继承自 A。 - Greg
1
@FreeAsInBeer:真的,认真点,深呼吸。你对“真相”和“正义”感到非常激动,但我们中没有人会被送到海牙(我希望如此)。简单地说,这个答案并不是很好。它甚至没有开始回答实际问题;记住,“为什么”问题应该用“因为”来回答;你给了一个“如何”回答,适用于一个“我怎样做”问题。把它看作一个学习机会;下次,认真阅读问题,并理解实际上被问的问题。 - Eric Lippert
2
@Eric,@Greg:谢谢。我感激你们的建设性批评,并希望未来能够提供更清晰的答案,更好地回答问题。 - FreeAsInBeer
显示剩余5条评论

2

您可以在 B 类本身中访问 Test int。 但是,您无法访问实例的属性。A 不知道它是 B 的子类,因此不会给予其属性访问权限。

class A
{
    protected int Test;
}
class B : A
{
    public B()
    {
       Test = 3; //possible
       base.Test = 3;  //explicitly calling base member, but not necessary in this case
    }
}

2

子类可以访问被标记为protected自己的继承成员。

class A
{
   protected int Test;
}

class B : A
{
   public B()
   {
     this.Test = 42; // Possible
   }
}

2
由于B已经继承了A,因此您不需要一个单独的A实例。
   public B()
   {
     this.Test = 1; //possible
   }

2
您可以通过相同的类访问它,而不是作为基类的公共成员访问。
class A 
{ 
    protected int Test; 
} 

class B:A 
{ 
    void TestMethod()
    {
         this.Test = 3; // Possible
    }
}

查看C#中的protected访问修饰符。


2

如果你继承了A,那么你不需要创建一个A实例。

class A
{
   protected int Test;
}
class B:A
{
   public B()
   {
     this.Test = 666;
   }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接