【问题标题】:Alternative to switch statement to call methods in c# [duplicate]c#中调用方法的switch语句的替代方法[重复]
【发布时间】:2019-08-05 17:51:30
【问题描述】:

我有一个方法,它使用switch语句根据输入参数调用其他方法,如下所示:

    switch (reportName)
            {
                case A:
                    return GenerateReportA(reportName, model, language);
                case B:
                    return GenerateReportB(reportName, model, language);
                case C:
                    return GenerateReportC(reportName, model, language);
                case D:
                    return GenerateReportD(reportName, model, language);
                case E:
                    return GenerateReportE(reportName, model, language);

                and so on...                    
            }

我知道随着越来越多的报告添加到系统中,这个 switch 语句会不断增加。有没有其他方法可以实现这一目标? ...代表? ……拉姆达?我只知道我的所有 GenerateReport 方法都将具有相同的签名。

【问题讨论】:

  • 你可以发Dictionary<string, Func<...>>
  • 您可以使用反射按名称查找方法,即var method = this.GetType().GetMethod($"GenerateReport{reportName}", null, BindingFlags.Instance | BindingFlags.NonPublic),然后调用它:return (Report)method.Invoke(new object[] { reportName, model, language });。如果这更容易编写,并不意味着它工作得更快。

标签: c# lambda delegates switch-statement


【解决方案1】:

正如SLaks 所说,您可以将您的开关重构为字典。我假设您的三个输入参数是字符串。根据需要进行调整:

// the dictionary value is a function delegate with three string input
// parameters and a string result
var _generateReport = new Dictionary<string, Func<string, string, string, string>>()
    { 
        {"A", GenerateReportA}, 
        {"B", GenerateReportB}, 
        {"C", GenerateReportC}, 
        {"D", GenerateReportD}, 
        {"E", GenerateReportE} 
        ...
    };

然后你可以将你的switch语句重写为

if (_generateReport.ContainsKey(reportName)) 
     _generateReport[reportName].Invoke(reportName, model, language); 

【讨论】:

    【解决方案2】:

    这对你来说可能有点矫枉过正,但你可以做这样的事情。我在研究 S.O.L.I.D(设计原则)的 O 部分时学到了这种方法。这种方法的好处是,当需要一个新报告时,您只需为它创建一个派生自 BaseReportGenerator 的类。我已经演示了使用程序集扫描获取相关类的方法,但另一种方法是将它们全部作为依赖项注入。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    
    namespace AltToSwitch
    {
        class Program
        {
            static void Main(string[] args)
            {
                var myReportType = "A";
                var model = "myModel";
                var language = "myLanguage";
    
                var reportGenerators = new List<BaseReportGenerator>();
    
                //use assembly scanning to get all report generator implementations
                foreach (Type type in
                    Assembly.GetAssembly(typeof(BaseReportGenerator)).GetTypes()
                    .Where(myType => myType.IsClass && !myType.IsAbstract && myType.IsSubclassOf(typeof(BaseReportGenerator))))
                {
                    reportGenerators.Add((BaseReportGenerator)Activator.CreateInstance(type));
                }
    
                var reportGeneratorToUse = reportGenerators.SingleOrDefault(x => x.ReportName == myReportType);
                Console.WriteLine(reportGeneratorToUse.GenerateReport(model, language));
            }
        }
    
        public abstract class BaseReportGenerator
        {
            public abstract string ReportName
            {
                get;
            }
            public abstract string GenerateReport(string model, string language);
    
            //common report functionality could go here
        }
        public class TheAReportGenerator : BaseReportGenerator
        {
            public override string ReportName => "A";
    
            public override string GenerateReport(string model, string language)
            {
                return "The A report";
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多