Question

Comment déclarez-vous une méthode en C # qui devrait être remplacée (ou substituable) par une classe dérivée - peut-être même en dehors de votre assembly - mais qui ne devrait être appelable que de la classe réelle?

(c'est-à-dire comme une fonction virtuelle privée en C ++)

[modifier]
privé virtuel correspond exactement à ce que je souhaite: "Voici un moyen de modifier mon comportement, mais vous n'êtes toujours pas autorisé à appeler cette fonction directement (parce que l'appel nécessite des invocations mystérieuses que seule ma classe de base doit faire) "

Donc pour clarifier: quelle est la meilleure expression pour cela en C #?

Était-ce utile?

La solution

C # offre une garantie plus forte pour "privé". que C ++. En C ++, vous pouvez en effet remplacer une méthode virtuelle privée. Mais cela signifie que le code d'une classe de base peut exécuter du code dans une classe dérivée. Rompre la promesse que la méthode privée est vraiment privée et ne peut être appelée que par des méthodes de la même classe.

Ce qui n’aide en rien ici, c’est que C ++ n’exige pas de répéter le mot clé virtuel. En route vers des techniques d’ingénierie inverse telles que celle-ci:

#include "stdafx.h"
#include <iostream>

class Base {
private:
    virtual void Method() = 0;
public:
    void Test() {
        Method();
    }
};
class Derived : public Base {
private:
    void Method() { std::cout << "Who the heck called me?"; }
};

int _tmain(int argc, _TCHAR* argv[])
{
    Base* p = new Derived;
    p->Test();
}

Je conviens qu'il y a un rôle possible pour l'héritage privé. Les concepteurs du langage C # ont dit non! bien que.

Autres conseils

Lorsque vous dites que cela ne devrait être appelable que "dans la classe actuelle" voulez-vous dire la classe de base ou la classe dérivée? Aucune de celles-ci n'est réalisable par elle-même. Le plus proche consiste à utiliser une méthode protégée, ce qui signifie qu’elle peut être appelée à partir de la classe déclarante, de la classe dérivée et de toute classe dérivée ultérieure.

Un membre privé n'est pas visible pour les classes enfants. Je pense que le virtuel protégé fonctionnera comme vous le souhaitez?

UPDATE:

Vous trouverez ici une explication plus détaillée de ce que vous pouvez faire avec l'héritage et les fonctions de substitution dans C #. J'ai essayé d'utiliser un exemple assez significatif, mais considérez qu'il est bien compris que sa conception de classe est médiocre et que je ne recommanderais jamais d'implémenter les classes décrites de cette manière. Cependant, j'espère que cela vous donnera peut-être un moyen d'aborder la résolution de votre problème initial d'une manière qui pourrait être acceptable. Il n’ya aucun moyen d’empêcher une classe concrète d’appeler un de ses membres, mais si votre structure est comme cela de toute façon, peut-être que ce n’est pas son problème.

public abstract class Animal
{
    public void DisplayAttributes()
    {
        Console.WriteLine(Header());
        Console.WriteLine("Name: " + Name());
        Console.WriteLine("Legs: " + Legs());
        Console.WriteLine();
    }

    protected virtual int Legs()
    {
        return 4;
    }

    private string Header()
    {
        return "Displaying Animal Attributes";
    }

    protected abstract string Name();
}

public class Bird : Animal
{
    protected override string Name()
    {
        return "Bird";
    }

    protected override int Legs()
    {
        return 2;
    }
}

public class Zebra : Animal
{
    protected override string Name()
    {
        return "Zebra";
    }
}

public class Fish : Animal
{
    protected override string Name()
    {
        return "Fish";
    }

    protected override int Legs()
    {
        return 0;
    }

    private string Header()
    {
        return "Displaying Fish Attributes";
    }

    protected virtual int Gils()
    {
        return 2;
    }

    public new void DisplayAttributes()
    {
        Console.WriteLine(Header());
        Console.WriteLine("Name: " + Name());
        Console.WriteLine("Gils: " + Gils());
        Console.WriteLine();
    }
}

class Program
{
    static void Main(string[] args)
    {
        Bird bird = new Bird();
        bird.DisplayAttributes();
        //Displaying Animal Attributes
        //Name: Bird
        //Legs: 2

        Zebra zebra = new Zebra();
        zebra.DisplayAttributes();
        //Displaying Animal Attributes
        //Name: Zebra
        //Legs: 4


        Fish fish = new Fish();
        fish.DisplayAttributes();
        //Displaying Fish Attributes
        //Name: Fish
        //Gils: 2

        List<Animal> animalCollection = new List<Animal>();
        animalCollection.Add(bird);
        animalCollection.Add(zebra);
        animalCollection.Add(fish);

        foreach (Animal animal in animalCollection)
        {
            animal.DisplayAttributes();
            //Displaying Animal Attributes
            //Name: Bird
            //Legs: 2

            //Displaying Animal Attributes
            //Name: Zebra
            //Legs: 4

            //Displaying Animal Attributes
            //Name: Fish
            //Legs: 0
            //*Note the difference here
            //Inheritted member cannot override the
            //base class functionality of a non-virtual member
        }
    }
}

Dans cet exemple, Bird, Zebra et Fish peuvent tous appeler leurs méthodes Name et Legs, mais dans le contexte, si cet exemple ne présente aucune utilité. De plus, comme le montre Fish, DisplayAttributes () peut être modifié pour une instance d’une classe dérivée concrète; mais quand vous regardez un animal, comme dans la boucle foreach, vous obtenez le comportement des classes de base DisplayAttributes, quel que soit le type d'animal. J'espère que cela vous aidera à définir le type de fonctionnalité que vous souhaitez répliquer.

Avez-vous envisagé de faire appel à un délégué? Vous pouvez autoriser la classe dérivée à définir le délégué via une propriété protégée ou à le transmettre à votre constructeur. Vous pouvez également définir par défaut le délégué de votre implémentation interne, qui est une méthode privée de votre classe de base.

Voici un exemple de ce que vboctor a déjà mentionné:

public class Base
{
    private Func<Base, int> func;
    protected void SetFunc(Func<Base, int> func)
    {
        this.func = func;
    }

    private void CallFunc()
    {
        if (func != null)
        {
            var i = func(this);
        }
    }
}

public class Sub : Base
{
    private void DoFuncyStuff()
    {
         this.SetFunc(b => 42);
    }
}

Pourquoi avez-vous besoin que ce soit privé? Protégé devrait être suffisant, ici. Vous demandez à l'auteur de la sous-classe d'écrire du code qu'il ne peut pas appeler. Qu'est-ce que cela accomplit? Ils pourraient quand même utiliser ce code.

En lisant votre question, vous pourriez dire deux choses.

Tout d'abord, si vous voulez une fonction de la classe A pouvant être remplacée dans la classe enfant B mais qui n'est visible par aucune classe extérieure:

public class ClassA
{
  protected virtual ReturnType FunctionName(...) { ... }
}

public class ClassB
{
  protected override ReturnType FunctionName(...) { ... }
}

Deuxièmement, si vous voulez forcer une classe d'implémentation à définir la fonction:

public abstract class ClassA
{
  protected abstract ReturnType FunctionName(...);
}

public class ClassB
{
  protected override ReturnType FunctionName(...) { ... }
}

Un autre concept que vous pourriez envisager si vous creusez juste en C # est un peu lié: les classes partielles. C’est l’idée de combiner deux fichiers source lors de la compilation pour créer une classe, tous deux issus du même assemblage:

Fichier 1:

public partial class ClassA
{
    private ReturnType FunctionName(...);
}  

Fichier 2:

public partial class ClassA
{
  //actual implimentation
  private ReturnType FunctionName(...){ ... }; 
}

Les partiels ne sont pas largement utilisés, sauf lorsqu'il s'agit de fichiers générés de manière ciblée, tels que les fichiers Linq2Sql, ou EDM, ou WinForms, etc.

Je suppose que cela ne fonctionnera pas comme vous le souhaitiez, mais permettez-moi d'esquisser un pseudo-code pour vous:

public interface BaseClassFunction {
    void PleaseCallMe();
}

public class BaseClass {
    private BaseClassFunction fn;
    public BaseClass(BaseClassFunction fn) {
        this.fn = fn;
    }
    private CallMe() {
        fn.PleaseCallMe();
    }
    public PublicCallMe() {
        CallMe();
    }
}

private class DerivedClassFunction : BaseClassFunction {
    void PleaseCallMe() { ... do something important ... }
}

public class DerivedClassFunction {
    public DerivedClassFunction() : BaseClass(new DerivedClassFunction()) {
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top