Question

Mon problème est que je voudrais passer un objet à une classe dérivée, mais il doit être fait avant que le constructeur de la classe de base, étant donné que la classe de base immédiatement appeler la méthode Start() de classe dérivée qui utilise l'objet.

Voici un extrait de la classe de base, (renommé de Barcodescanner pour plus de commodité).

public abstract class MyBase
{    
    public MyBase()
    {
        if (Initialize())
            this.Start();
    }

    public abstract bool Initialize();
    public abstract void Start();
}

Voici la classe dérivée que je crée.

class MyDerived : MyBase
{
    private string sampleObject;

    public MyDerived (string initObject)
    {
        sampleObject = initObject;
    }

    public override bool Initialize() 
    { 
        return GetDevice();
    }
    public override void Start() 
    { 
        Console.WriteLine("Processing " + sampleObject.ToString()); 
    }
}

Je doute que vous pouvez faire exécuter C # un constructeur dérivé avant que le constructeur de base; donc je suis vraiment à la recherche d'une solution pour passer un objet à la classe dérivée avant que l'objet est utilisé.

J'ai eu cela en mettant l'Initialiser / Start si le bloc dans le constructeur de MyDerived. Cependant, il existe d'autres classes dérivées de la classe de base; donc je fini par avoir à répéter ce bloc de code Initialiser / Start dans chaque classe dérivée. Je voudrais voir une alternative à la modification de la classe de base.

Était-ce utile?

La solution

Qu'est-ce que vous essayez de faire est impossible en C #. Un constructeur dans une classe de base doit être exécutée avant sinon le constructeur de toute classe dérivée, il serait possible pour l'état d'objet corrompu. Un objet enfant doit pouvoir supposer que sa base est entièrement construite et disponible.

Autres conseils

IMHO votre conception est erronée. Vous ne devriez pas démarrer le processus à partir du constructeur. Votre code doit appeler explicitement consommer la méthode Start () lorsque cela est nécessaire.

Je réusinage votre conception afin que Initialize (et potentiellement de démarrage () - bien que je serais normalement ce soit une méthode publique qui est appelée par l'utilisateur) sont appelés après la construction

.

Si vous faites un Barcodescanner, vous pouvez le faire la première fois que vous allez à numériser. Paresseux-initialiser vos membres en utilisant les données de la classe dérivée.

Cela fonctionne autour de votre question, sans changement réel dans l'utilisation de l'utilisateur.

Désolé pour ajouter à un vieux fil, mais peut-être quelqu'un est intéressé par une autre réponse. J'ai trouvé un (OMI) belle façon de gérer la logique de faire quelque chose de plus que (et après) seulement assignant des champs dans les constructeurs de classe où l'héritage est impliqué ici . Si vous voulez juste avoir si cette hiérarchie spécifique et ne pas utiliser la solution générique avec une interface et une méthode d'extension, vous pouvez utiliser le même concept dans un arbre de classe comme ceci:

public abstract class MyBase
{    
    protected MyBase()
    {
        if (Initialize(this)) // just to illustrate; this will never pass here as this class is abstract
            this.Start();
    }

    protected bool IsInitialized { get; private set; } = false;

    protected static bool Initialize<T>(T instance) where T: MyBase
    {
        if (instance?.GetType() == typeof(T)) // check if this is called from the constructor of instance run time type
            return instance.IsInitialized || ( instance.IsInitialized = instance.Initialize() );
        return false;
    }

    protected abstract bool Initialize();
    public abstract void Start();
}

et dérivés:

class MyDerived : MyBase
{
    private string sampleObject;
    protected bool started = false;

    public MyDerived (string initObject)
    {
        sampleObject = initObject;
        if (Initialize(this)) // if this is the most derived constructor, this will run Initialize() and return whether it was successful
            this.Start();
    }

    protected override bool Initialize() 
    { 
       return GetDevice();
    }

    public override void Start() 
    { 
        // if Start() would be protected, we don't need the IsInitialized property and we can move this check to the constructor on the returned value of the Initialize<T>() call.
        if (!IsInitialized) throw new InvalidOperationException("Initialization failed.");
        // if you want to have this method exposed public, we need to check if this instance is successfully initialized from the constructor and not in started state already.
        if (started) return;

        Console.WriteLine("Processing " + sampleObject.ToString()); 
        started = true;
        if (!Run(sampleObject)) started = false;
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top