2010-01-21 7 views
6
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 ? 
    } 
} 

Dans le code ci-dessus (compilé sur VS2005), je reçois les éléments suivants Compile Erreur de temps -Retour aux sources - C# Erreur du compilateur

Erreur 1 Impossible d'accéder membre protégé « BaseClass.BaseMethod() 'via un qualificateur de type' BaseClass '; le qualificatif doit être de type « ClasseDérivée » (ou dérivé de celui-ci)

Quelqu'un peut-il expliquer ce comportement? Quelque chose va fondamentalement mal ici!

Répondre

15

Eric Lippert juste blogged on this very topic. L'essentiel est de s'assurer qu'une classe peut "faire confiance" à l'appelant d'une méthode protégée. Les classes qui partagent une classe de base commune - même si cette base commune définit la méthode protégée - sont essentiellement des étrangers à cet égard.

L'exemple d'Eric est basé sur l'idée d'une application bancaire. Plutôt que de recréer son exemple, je vais régurgiter ici:

// 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. 
    } 
} 

Alors ce que vous présentez comme semble une évidence, si elle était autorisée à se produire alors le genre de manigances que vous voyez ici serait possible. En ce moment vous savez qu'un appel de méthode protégée vient soit de votre type (que vous contrôlez) soit d'une classe dont vous héritez directement (que vous connaissez au moment de la compilation). Si elle était ouverte à quelqu'un qui a hérité du type déclarant, alors vous n'auriez jamais la certitude de connaître les types qui peuvent appeler votre méthode protégée. Pendant que vous initialisez votre variable BaseClass à une instance de votre propre classe, le compilateur voit seulement que la variable est de type BaseClass, vous mettant en dehors du cercle de confiance. Le compilateur n'analyse pas tous les appels d'affectation (ou les appels d'affectation potentiels) pour déterminer s'il est "sûr".

+0

Merci Adam :) Cela a été très utile. – DotNetGuy

+0

@DotNetGuy: Merci; Si cela répond à votre question, n'oubliez pas de la marquer comme votre réponse acceptée afin que les autres puissent trouver plus facilement la réponse. –

2

De la spécification C#:

Lorsqu'un membre d'instance protégé est accessible en dehors du texte du programme de la classe dans laquelle elle est déclarée, et quand on accède à un membre exemple interne protégé en dehors de la programme texte du programme dans lequel il est déclaré, l'accès est requis pour avoir lieu à travers une instance du type de classe dérivé dans lequel se produit l'accès .

Lien MSDN here.

1

Cela provient directement de MSDN: http://msdn.microsoft.com/en-us/library/bcd5672a%28VS.71%29.aspx

Un membre protégé d'une classe de base est accessible dans une classe dérivée uniquement si l'accès se fait par le type de classe dérivée. Par exemple, considérons le segment de code suivant:

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