简体   繁体   中英

Using delegate and inheritance to define which method is run inside the child class

I have a child and a parent class in C#. I want to point the Calc delegate to one of several methods. this is determined each time the Reset() method is called. Below is a working example. However, I want this functionality of pointing the delegate to reside on the Parent class. Since the parent does not contain the methods, I don't know how to do it...

    class Program
{
    static void Main(string[] args)
    {
        Model Model = new Model();
        Model.Env1 = true;
        Child Ch = new Child(Model);
        Ch.Reset();
        Ch.Calc(); Ch.Calc(); Ch.Calc();
        Console.WriteLine();
        Model.Env1 = false;
        Ch.Reset();
        Ch.Calc(); Ch.Calc(); Ch.Calc();
        Console.ReadLine();
    }
}

public class Parent
{
    public Model Model { get; set; }
    public Parent(Model model)
    {
        Model = model;
    }
    public delegate void StateHandler();
    public StateHandler Calc;
}
public class Model
{
    public bool Env1 { get; set; }
}
public class Child : Parent, IChild
{
    public Child (Model model)
        : base (model)
    {
    }
    public void Reset()
    {
        if (Model.Env1)
            Calc = CalcHeavy;
        else
            Calc = CalcLight;
    }
    public void CalcHeavy()
    {
        Console.WriteLine("CalcHeavy is active");
    }
    public void CalcLight()
    {
        Console.WriteLine("CalcLight is active");
    }
}
public interface IChild
{
    void CalcHeavy();
    void CalcLight();
}

One way to do that would be to have the Child class inject its methods into the Parent at construction time. That way, the Parent class makes the choice, but the Child class defines the functionality:

public class Parent
{
    private readonly Action _env1Method;
    private readonly Action _notEnv1Method;
    private readonly Model _model;

    public Parent(Model model, 
                  Action env1Method, 
                  Action notEnv1Method)
    {
        _model = model;
        _env1Method = env1Method;
        _notEnv1Method = notEnv1Method;
        Reset();
    }

    public Action Calc { get; private set; }

    public void Reset()
    {
        Calc = _model.Env1 ? _env1Method : _notEnv1Method;
    }
}

public class Model
{
    public bool Env1 { get; set; }
}

public class Child : Parent
{
    public Child (Model model) : base (model, CalcHeavy, CalcLight) {}

    private static void CalcHeavy()
    {
        Console.WriteLine("CalcHeavy is active");
    }

    private static void CalcLight()
    {
        Console.WriteLine("CalcLight is active");
    }
}

Also, I'd get rid of StateHandler and just use Action instead. Don't create a new delegate when a standard one exists already.

While trying to get the answer I liked to work, I managed to solve it in a different way by making the Parent abstract, and it works.

    class Program
{
    static void Main(string[] args)
    {
        Model Model = new Model();
        Model.Env1 = true;
        Child Ch = new Child(Model);

        Ch.Calc(); Ch.Calc(); Ch.Calc();
        Console.WriteLine();
        Model.Env1 = false;

        Ch = new Child(Model);
        Ch.Calc(); Ch.Calc(); Ch.Calc();
        Console.ReadLine();
    }
}

public abstract class Parent
{
    public Model Model { get; set; }
    public Parent(Model model)
    {
        Model = model;
        if (Model.Env1)
            Calc = CalcHeavy;
        else
            Calc = CalcLight;
    }

    public Action Calc;

    public abstract void CalcHeavy();
    public abstract void CalcLight();

}
public class Model
{
    public bool Env1 { get; set; }
}
public class Child : Parent
{
    public Child(Model model) : base(model) { }

    public override void CalcHeavy()
    {
        Console.WriteLine("CalcHeavy is active");
    }
    public override void CalcLight()
    {
        Console.WriteLine("CalcLight is active");
    }
}

One way is to move the "Reset" method to the parent class and do something like this:

public void Reset()
{
       var child = this as IChild;

        if (child != null && Model.Env1)
            Calc = child.CalcHeavy;
        else
            Calc = child.CalcLight;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM