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

C# 如何在运行时重载方法或C中的其他想法#,c#,runtime,overloading,C#,Runtime,Overloading,也许重载一个方法并不完全是必要的,但这是我能想到的最好的方法 我有一门课: public class Worker { private string jobType; public Worker(string jt) { this.jobType = jt; } public void ProcessJob() { if(jobType.Equals("Pizza") MakePizza();

也许重载一个方法并不完全是必要的,但这是我能想到的最好的方法

我有一门课:

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
    }
}
以上只是一个示例。当类被构造时,它是用特定的作业类型构造的,并且不会改变。然而,它可能需要执行数以百万计的工作,总是相同类型的。
ProcessJob()
将一直被调用,但调用者不知道这是什么类型的工作者。我希望避免每次都运行if检查,必须有一种方法只执行一次检查并准备它


在我的案例中,制作儿童课程(披萨工人、汉堡工人等)不是一个选择,因为在我的真实案例中,课程很大,只有一个微小的区别。更改它将影响整个体系结构,因此需要避免。

这正是存在模式的原因:

我相信你正在寻找的是命令模式。首先,您有一个基本的“命令”模板:

public interface IJob {
    void ProcessJob();
}
然后将按如下方式执行不同的作业:

public class MakePizza : IJob {
    // implement the interface
    public void ProcessJob() {
        // make a pizza
    }
}
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
    }
}
现在,您可以有一个JobFactory,如下所示:

public class MakePizza : IJob {
    // implement the interface
    public void ProcessJob() {
        // make a pizza
    }
}
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现在可以如下所示:

public class Worker {
    private IJob job;

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

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

如果您没有进行这些更改的代码访问权限,那么您可能需要研究的另一种模式是。

您可以使用在构建对象时创建的委托,这样可以自动完成分派:

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

你说的是基本的继承权。有几种方法可以做到这一点

创建一个基类

public class Job
{
    virtual void ProcessJob();
}
然后是
MakePizza

public class MakePizza : Job
{
    public void ProcessJob()
    {
       //make Pizza
    }
}
然后在worker类中,而不是将JobType作为
字符串
,这将导致各种潜在的bug

public class Worker{


  private Job jobType;


  public Worker(Job jt){

    this.jobType = jt;
  }


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

}

如果必须传递字符串,只需通过反射加载JobType,如果类型不存在则抛出错误。

我仍然建议使用子类。如果无法从Worker继承,则创建在Worker内部使用的新类层次结构。这样,任何使用工人类的人都不必知道有子类。若你们真的讨厌子类,或者你们有其他原因不想要它们,你们可以使用字典。它包含作业类型作为键,操作作为它调用的方法。如果需要更多作业,只需创建私有方法并在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();
}
private Dictionary actions=new Dictionary();
公共工作者(字符串jt)
{
this.jobType=jt;
这是RegisterWorkers();
}
私人无效登记员
{
this.actions[“Pizza”]=this.MakePizza;
this.actions[“Burger”]=this.MakeBurger;
}
public void ProcessJob()
{
var action=this.actions[this.jobType];
动作();
}

不,我认为不应该避免。任何通用功能都应该放在基类中。我认为您需要一个static,它根据string参数返回一个子类

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();
    }
}
所以要使用这个:

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

创建一个抽象基类,其中包含工作人员可以执行的常见操作。然后为专业工作者声明派生类

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
    }
}
现在,您可以创建不同类型的工人,并让他们完成自己的工作:

var workers = new List<Worker>();
workers.Add(new PizzaWorker());
workers.Add(new BurgerWorker());
foreach (Worker worker in workers) {
    woker.ProcessJob();
}
var workers=newlist();
添加(新PizzaWorker());
添加(新工人());
foreach(工人中的工人){
woker.ProcessJob();
}
这将自动为每种类型的工作人员调用正确的
ProcessJob



注意:If-else-If级联和switch语句通常表示代码以过程方式而不是面向对象的方式工作。将其重构为面向对象的

必须更改其他类意味着您需要更改代码,而不是更改体系结构。最好的答案就是更改代码。从长远来看,必须以一种不太理想的方式编写此代码所带来的维护负担将比仅仅更改代码花费更多。使用继承并咬紧牙关立即进行更改。如果您的迭代器在处理子类型时遇到问题,那么您的迭代器所做的不仅仅是作为迭代器,而且您最好修复它,而不是继续使用它们。如果其他类关心它们所处理的工人的子类型,那么这本身就是一个问题,您应该解决这个问题。最终,依赖代码不应该关心它是哪种类型的工作者。这才是你真正想要的。以work作为其基类型的类型的实例仍然是一个worker,这是使用worker的类应该关心的所有问题。

“类很大,只有一个微小的区别。”这是OOP的要点之一。再次解释为什么继承不是一个选项?这些对象已经由列表中的其他类构建和维护。有很多迭代器,如果我创建了不同的类,那么需要重写迭代器以便动态生成它们吗?是否可以将委托存储在
字典中
中?正如minitech所指出的,存在差异很小的继承是它存在的原因。无论何时使用switch语句,都可能会错过继承解决方案。在这种情况下,基类应该有一个Run方法,而你有一个Pizza,Burger类,它继承并实现了抽象Run。-1:我不认为这个特定的例子是可靠的-尤其是在开放封闭区域。如果需要新的作业类型,则您正在修改此
工作者
类。@IAbstract IMO这是最好的选择,因为OP希望避免创建派生类。要避免创建更多派生类,这将起作用,是的……但是,IMHO这是一个短期的“修复”…:)我不打算攻击你,但我认为值得注意的是,虽然这可能会提供OP想要听到的答案,但现在正确地做这件事将使以后的生活更加轻松。我喜欢这种方法以及命令模式。两个同样可接受的解决方案-尽管