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".
Merci Adam :) Cela a été très utile. – DotNetGuy
@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. –