Domanda

Come si dichiara un metodo in C # che dovrebbe essere sovrascritto (o sovrascrivibile) da una classe revocata - possibilmente anche al di fuori dell'assembly - ma che dovrebbe essere richiamabile solo dall'interno della classe attuale?

(ovvero come una funzione virtuale privata in C ++)

[modifica]
privato virtual è esattamente ciò che intendo: " Ecco un modo per modificare il mio comportamento, ma non ti è ancora consentito chiamare questa funzione direttamente (perché chiamarlo richiede invocazioni arcane che solo la mia classe base deve fare) "

Quindi, per chiarirlo: qual è la migliore espressione per quello in C #?

È stato utile?

Soluzione

C # offre una garanzia più forte per " private " di C ++. In C ++, puoi davvero sovrascrivere un metodo virtuale privato. Ciò significa che il codice in una classe base può eseguire il codice in una classe derivata. Rompere la promessa che il metodo privato è veramente privato e può essere chiamato solo da metodi della stessa classe.

Qualcosa che non aiuta qui è che C ++ non richiede di ripetere la parola chiave virtuale. Portando a misteri difficili da decodificare come questo:

#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();
}

Sono d'accordo che ci sia un possibile ruolo per l'eredità privata. I progettisti del linguaggio C # hanno detto No! però.

Altri suggerimenti

Quando dici che dovrebbe essere richiamabile solo all'interno della classe effettiva " intendi la classe base o la classe derivata? Nessuno di questi è fattibile da solo. Il più vicino è usare un metodo protetto, il che significa che può essere chiamato dalla classe dichiarante, dalla classe derivata e da qualsiasi altra classe derivata.

Un membro privato non è visibile alle classi secondarie. Penso che il virtuale protetto si comporterà nel modo desiderato?

UPDATE:

Qui in maggior dettaglio è una spiegazione di cosa si può fare con l'ereditarietà e le funzioni prioritarie in C #. Ho cercato di usare un esempio in qualche modo significativo, ma ritengo che abbia capito che si tratta di un progetto di classe scadente e non consiglierei mai di implementare le classi descritte in questo modo. Tuttavia, spero che questo possa darti una strada per avvicinarti a risolvere il tuo problema originale in un modo che potrebbe essere accettabile. Non c'è modo di impedire a una classe concreta di chiamare qualcuno dei suoi membri, ma se la tua struttura è comunque così, forse non è un problema.

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

In questo esempio, Bird, Zebra e Fish potrebbero tutti chiamare i loro metodi Name e Legs, ma nel contesto se questo esempio non ci fosse necessariamente utilità nel farlo. Inoltre, come mostrato da Fish, DisplayAttributes () può essere modificato per un'istanza di una classe derivata dal calcestruzzo; ma quando guardi un animale, come nel ciclo foreach, ottieni il comportamento DisplayAttributes delle classi base, indipendentemente dal tipo reale di animale. Spero che ciò possa aiutare a promuovere il tipo di funzionalità che desideri replicare.

Hai considerato l'uso di un delegato per farlo? È possibile consentire alla classe derivata di impostare il delegato tramite una proprietà protetta o passandolo al costruttore. Puoi anche impostare il delegato come predefinito sull'implementazione interna, che è un metodo privato sulla tua classe base.

Ecco un esempio di ciò che vboctor ha già menzionato:

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

Perché ne hai bisogno per essere privato? Protetto dovrebbe essere sufficiente, qui. Stai chiedendo all'autore della sottoclasse di scrivere codice che non possono chiamare. Cosa compie questo? Potrebbero comunque usare quel codice.

Mentre leggo la tua domanda, potresti significare due cose.

Innanzitutto, se si desidera una funzione in Classe A che può essere sostituita in Classe figlio B ma non è visibile a nessuna classe esterna:

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

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

In secondo luogo, se si desidera forzare una classe di implementazione per definire la funzione:

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

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

Un altro concetto che potresti prendere in considerazione se stai scavando in C # che è in qualche modo correlato sono le classi parziali. Questa è l'idea di due file sorgente combinati in fase di compilazione per creare una classe, entrambi dallo stesso assembly:

File 1:

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

File 2:

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

I parziali non sono ampiamente utilizzati tranne quando si tratta di file generati dal design, come i file Linq2Sql, o EDM, o WinForms, ecc.

Suppongo che questo non funzionerà come previsto, ma lasciami fare uno schizzo di pseudo-codice per te:

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()) {
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top