Назад к основам - Ошибка компилятора C#

public class BaseClass 
{
  protected void BaseMethod() 
  { 

  }
}

public class DerivedClass : BaseClass 
{
  public void Test() 
  {
    DerivedClass d1 = new DerivedClass();
    d1.BaseMethod(); // No error here.        

    BaseClass b1 = new DerivedClass();
    b1.BaseMethod(); // I get compile-time error for this. Why ? 
  }
}

В вышеупомянутом коде (скомпилированный на VS2005), я получаю следующую Ошибку времени компиляции -

Ошибка 1 не Может получить доступ к защищенному участнику 'BaseClass. BaseMethod ()' через спецификатор типа 'Базовый класс'; спецификатор должен иметь тип 'DerivedClass' (или полученный из него)

Кто-то может объяснить это поведение? Что-то идет существенно неправильно сюда!

6
задан Eric Lippert 22 January 2010 в 18:37
поделиться

3 ответа

Эрик Липперт только вспомогал эту очень тему .

Основной судьей этого является обеспечение того, чтобы класс мог «доверять» абоненте защищенного метода. Классы, которые разделяют общий базовый класс - даже если эта общая база определяет защищенный метод - по сути незнакомцы в этом отношении.

Пример Эрика основан на идее приложения банка. Вместо того, чтобы воссоздать свой пример, я просто обмургирую это здесь:

// Good.dll:

public abstract class BankAccount
{
  abstract protected void DoTransfer(
    BankAccount destinationAccount, 
    User authorizedUser,
    decimal amount);
}
public abstract class SecureBankAccount : BankAccount
{
  protected readonly int accountNumber;
  public SecureBankAccount(int accountNumber)
  {
    this.accountNumber = accountNumber;
  }
  public void Transfer(
    BankAccount destinationAccount, 
    User authorizedUser,
    decimal amount)
  {
    if (!Authorized(user, accountNumber)) throw something;
    this.DoTransfer(destinationAccount, user, amount);
  }
}
public sealed class SwissBankAccount : SecureBankAccount
{
  public SwissBankAccount(int accountNumber) : base(accountNumber) {}
  override protected void DoTransfer(
    BankAccount destinationAccount, 
    User authorizedUser,
    decimal amount)
  {
    // Code to transfer money from a Swiss bank account here.
    // This code can assume that authorizedUser is authorized.
    // We are guaranteed this because SwissBankAccount is sealed, and
    // all callers must go through public version of Transfer from base
    // class SecureBankAccount.
  }
}
// Evil.exe:
class HostileBankAccount : BankAccount
{
  override protected void Transfer(
    BankAccount destinationAccount, 
    User authorizedUser,
    decimal amount) {  }
  public static void Main()
  {
    User drEvil = new User("Dr. Evil");
    BankAccount yours = new SwissBankAccount(1234567);
    BankAccount mine = new SwissBankAccount(66666666);
    yours.DoTransfer(mine, drEvil, 1000000.00m); // compilation error
    // You don't have the right to access the protected member of
    // SwissBankAccount just because you are in a
    // type derived from BankAccount.
  }
}

, в то время как то, что вы представляете, кажется, не мозги, если бы ему было позволено случиться, то такого рода шинаниганов, которые вы видите здесь. Сейчас вы знаете , что охраняемый вызов метода либо исходит от вашего типа (который у вас есть контроль) или из класса, который вы напрямую наследуете (который вы знаете во время того, как вы компилируете). Если бы он был открыт для всех, кто унаследовал от типа декларирования, то у вас никогда не будет поручительно знания типов, которые могут позвонить вашему защищенному методу.

В то время как вы инициализируете вашу BaseClass , переменную в экземпляр вашего собственного класса, компилятор видит только то, что переменная имеет тип BaseClass , выдвигая вас за пределами круга доверять. Компилятор не анализирует все вызовы присваиваний (или потенциальных вызовов присваивания), чтобы определить, является ли это «безопасным».

15
ответ дан 8 December 2019 в 12:59
поделиться

из спецификации C #:

Когда защищенный элемент экземпляра доступ к тексту программы класс, в котором он объявлен, и Когда защищенный внутренний экземпляр Участник находится за пределами программы текст программы, в которой это заявлен, доступ должен проходить через экземпляр Тип полученного класса, в котором доступ имеет место.

MSDN Link здесь .

2
ответ дан 8 December 2019 в 12:59
поделиться

Это воспринимается непосредственно из MSDN: http://msdn.microsoft.com/en-us/library/bcd5672a%28vs.71%29.aspx

Защищенный элемент базового класса доступен В полученном классе только если доступ проходит через полученный тип класса. Например, рассмотрим следующий сегмент кода:

class A 
{
   protected int x = 123;
}

class B : A 
{
   void F() 
   {
      A a = new A();  
      B b = new B();  
      a.x = 10;   // Error
      b.x = 10;   // OK
   }
}
1
ответ дан 8 December 2019 в 12:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: