简体   繁体   English

如何在运行时重载方法或C#中的其他想法

[英]How to overload a method at run-time or other ideas in C#

Maybe overloading a method is not exactly what is necessary but this is the best i could come up with. 也许重载方法并不完全是必需的,但这是我能想到的最好的方法。

I have a class: 我有一堂课:

public class Worker {
    private string jobType;

    public Worker(string jt)
    {
        this.jobType = jt;
    }

    public void ProcessJob()
    {
         if(jobType.Equals("Pizza") MakePizza();
         else if (jobType.Equals("Burger") MakeBurger();
    }

    private void MakePizza()
    {
        // make pizza
    }

    private void MakeBurger()
    {
        // make burger
    }
}

The above is just an example of illustration. 以上仅是示例。 When the class is constructed, it is constructed with a specific job type, and that won't change. 构造类时,将使用特定的作业类型来构造类,并且该类不会改变。 However it may need to perform millions of jobs, always of the same type. 但是,它可能需要执行数百万个始终相同类型的工作。 The ProcessJob() will be called all the time, but the caller won't know what type of worker this is. ProcessJob()将一直被调用,但是调用者将不知道这是什么类型的工作器。 I would like to avoid running the if check every single time, there has to be a way to do that check only once and prep it. 我想避免每次都运行if检查,必须有一种方法只能执行一次检查并进行准备。

In my case, making child classes (pizza worker, burger worker, etc.) is not an option, as in my real case, the class is large and there is only one tiny difference. 在我的情况下,让孩子上课(披萨工人,汉堡工人等)不是一种选择,因为在我的实际情况下,班级很大,只有一个微小的区别。 Changing it will impact the whole architecture so it needs to be avoided. 更改它会影响整个体系结构,因此需要避免。

Create an abstract base class, which contains common things a worker can do. 创建一个抽象基类,其中包含工作人员可以执行的常见操作。 Then declare derived classes for specialized workers. 然后为专业工作者声明派生类。

public abstract class Worker
{    
    public abstract void ProcessJob();
}

public class PizzaWorker : Worker
{
    public override void ProcessJob()
    {
        // Make pizza
    }
}

public class BurgerWorker : Worker
{
    public override void ProcessJob()
    {
        // Make burger
    }
}

Now you can create workers of different types and let them do their job: 现在,您可以创建不同类型的工人,并让他们完成工作:

var workers = new List<Worker>();
workers.Add(new PizzaWorker());
workers.Add(new BurgerWorker());
foreach (Worker worker in workers) {
    woker.ProcessJob();
}

This will automatically call the right implementation of ProcessJob for each type of worker. 这将自动为每种类型的工作程序调用正确的ProcessJob实现。


Note: If-else-if cascades and switch statements are often an indication that the code works in a procedural rather than object-oriented way. 注意:if-else-if级联和switch语句通常表明该代码以过程方式而不是面向对象的方式工作。 Refactor it to be object-oriented! 将其重构为面向对象!

You could use a delegate created when the object is constructed, this way the dispatch is done automatically: 您可以使用在构造对象时创建的委托,这样可以自动完成分派:

public class Worker
{
    private delegate void MakeSomething();

    private MakeSomething makeWhat;
    private string jobType;

    public Worker(string jt)
    {
        this.jobType = jt;

        switch (jt)
        {
            case "Pizza":
                makeWhat = new MakeSomething(MakePizza);
                break;
            case "Burger":
                makeWhat = new MakeSomething(MakeBurger);
                break;
            default:
                throw new ArgumentException();
        }
    }

    public void ProcessJob()
    {
        makeWhat();
    }

    private void MakePizza()
    {
        //make pizza
    }

    private void MakeBurger()
    {
        //make burger
    }
}

This is exactly why there are patterns: Command , Strategy , Decorator . 这就是为什么有模式的原因: CommandStrategyDecorator

I believe the command pattern is what you are looking for. 我相信您正在寻找的命令模式。 First you have a basic 'command' template: 首先,您有一个基本的“命令”模板:

public interface IJob {
    void ProcessJob();
}

Different jobs would then be performed as follows: 然后将执行以下不同的作业:

public class MakePizza : IJob {
    // implement the interface
    public void ProcessJob() {
        // make a pizza
    }
}

Now, you could have a JobFactory as follows: 现在,您可以拥有一个JobFactory,如下所示:

public static class JobFactory {
    public static IJob GetJob(string jobType) {    
        if(jobType.Equals("Pizza"){
            return new MakePizza();
        } else (jobType.Equals("Burger") {
            return new MakeBurger();
        }
        // to add jobs, extend this if-else-if or convert to switch-case
    }
}

Worker can now look like this: 工人现在可以如下所示:

public class Worker {
    private IJob job;

    public Worker(string jt) {
        job = JobFactory.GetJob(jt);
    }

    public void ProcessJob() {
         job.ProcessJob();
    }
}

If you don't have access to code to make these changes, then another pattern you may want to look into is the Adapter . 如果您无权进行这些更改,那么您可能要研究的另一种模式是Adapter

I would still recommend to use sub classes. 我仍然建议使用子类。 If you cannot inherit from Worker then create new class hierarchy that is used inside the worker. 如果您不能从Worker继承,则创建在worker内部使用的新类层次结构。 This way anyone using Worker class doesn't have to know that there are sub classes. 这样,使用Worker类的任何人都不必知道存在子类。 If you really really hate sub classes or you have some other reason you don't want them you can use dictionary. 如果您真的很讨厌子类,或者您有其他原因不希望使用它们,则可以使用字典。 It contains job type as key and Action as the method it calls. 它包含作业类型作为键,并包含操作作为其调用的方法。 If you need more jobs just create the private method and register it in the RegisterWorkers method. 如果您需要更多工作,只需创建私有方法并在RegisterWorkers方法中注册它即可。

private Dictionary<string, Action> actions = new Dictionary<string, Action>();

public Worker(string jt)
{
    this.jobType = jt;
    this.RegisterWorkers();
}

private void RegisterWorkers
{
    this.actions["Pizza"] = this.MakePizza;
    this.actions["Burger"] = this.MakeBurger;
}

public void ProcessJob()
{
    var action = this.actions[this.jobType];
    action();
}

No, I don't think it should be avoided. 不,我认为不应避免。 Any common functionality should go in a base class. 任何常见的功能都应该放在基类中。 I think you need a static factory method , that returns a child class based on the string parameter. 我认为您需要一个静态工厂方法 ,该方法基于字符串参数返回一个子类。

public abstract class Worker {
    public virtual void ProcessJob();

    public static Worker GetWorker(string jobType) {
        if(jobType.Equals("Pizza")
            return new PizzaWorker();
        else if (jobType.Equals("Burger")
            return new BurgerWorker();
        else
            throw new ArgumentException();
    }

    // Other common functionality
    protected int getFoo() {
        return 42;
    }
}

public class PizzaWorker : Worker {
    public override void ProcessJob() {
        // Make pizza
        int y = getFoo() / 2;
    }
}

public class BurgerWorker : Worker {
    public override void ProcessJob() {
        // Make burger
        int x = getFoo();
    }
}

So to use this: 所以使用这个:

Worker w = Worker.GetWorker("Pizza");
w.ProcessJob();   // A pizza is made.

You're talking about basic inheritance here. 您在这里谈论的是基本继承。 There are a couple of ways that you could do this. 您可以通过两种方法来执行此操作。

Make a Base Class that is 使一个基类是

public class Job
{
    virtual void ProcessJob();
}

Then a MakePizza class 然后是MakePizza

public class MakePizza : Job
{
    public void ProcessJob()
    {
       //make Pizza
    }
}

Then in your worker class instead of having a JobType as a string which will lead to all kinds of potential bugs. 然后在您的worker类中,而不是将JobType作为string ,这将导致各种潜在的错误。

public class Worker{


  private Job jobType;


  public Worker(Job jt){

    this.jobType = jt;
  }


  public void ProcessJob()
  {
    Job.ProcessJob();  
  }

}

If you have to pass through a string you could simply load up the JobType through reflection, throwing a error if the type doesn't exist. 如果必须通过字符串,则可以通过反射简单地加载JobType,如果类型不存在,则抛出错误。

having to change other classes means you need to change code, not that you need to change architecture. 必须更改其他类意味着您需要更改代码,而不是需要更改体系结构。 the best answer is just to change the code. 最好的答案就是更改代码。 in the long term, the maintenance burden of having to write this in a less-than-ideal fashion will cost you more than just changing the code. 从长远来看,不得不以不理想的方式编写代码的维护负担将使您付出的代价不仅仅是更改代码。 use inheritance and bite the bullet on making the change now. 使用继承并立即做出更改。 if you have iterators that will have problems with dealing with subtypes, your iterators are doing more than being iterators, and you are better off fixing that than going forward with them. 如果您的迭代器在处理子类型时会遇到问题,那么您的迭代器所要做的不只是作为迭代器,而且与解决这些问题相比,最好将其修复。 if the other classes care about what subtype of worker they are dealing with, that's a problem in and of itself that you should fix. 如果其他类关心他们正在处理的工作者的子类型,那么这本身就是一个问题,您应该解决。 ultimately, the dependent code should not care which type of worker it is. 最终,从属代码不应关心它是哪种类型的工作程序。 that's really what you are after anyway. 无论如何,那确实是你想要的。 the instance of a type that has work as its base type is still a worker and that is all the class using a worker should care about. 具有工作作为其基本类型的类型的实例仍然是worker,而使用该worker的所有类都应该关心它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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