将类型传递为Type而不是string paramater

时间:2016-10-07 14:44:59

标签: c# asp.net .net

我想转换它(这很容易出错)....

    public static void GenerateReport(string report)
    {
        switch (report)
        {
            case "ReportA":
                // do stuff
                break;
            case "ReportB":
                // do stuff
                break;
            case "ReportC":
                // do stuff
                break;
        }
    }

对此......

    public static void GenerateReport<T>()
    {
        switch (T) // BUT.... how do I handle this?
        {
            case ReportA:
                // do stuff
                break;
            case ReportB:
                // do stuff
                break;
            case ReportC:
                // do stuff
                break;
        }
    }

我看到很多问题要求几乎同样的事情,但没有一个问题让我得到答案。像this one一样,但对我来说,该线程中提供的解决方案不起作用。当我尝试编译时,它会抛出多个语法错误。那里的解决方案说:

switch typeof(T) { 
    // 
}

4 个答案:

答案 0 :(得分:3)

你不需要泛型,也不需要带有类型检测的switch语句......而是使用每种类型的方法重载,并在自己的方法中保留做东西部分。

public static void GenerateReport(ReportA a) { /*do stuff*/ }
public static void GenerateReport(ReportB b) { /*do stuff*/ }
public static void GenerateReport(ReportC c) { /*do stuff*/ }

答案 1 :(得分:1)

关于泛型的关键点在于,如果你正在做的事情并不是每个最终T大致相同的,那么它就是&实际上泛型并且您不应该这样做。

这里好的候选人可能包括:

  • 一个枚举
  • 多态(virtual / abstract方法)
  • 传入Type实例

但......不是泛型。语言不能帮助你的原因是因为这不是一个合适的选择。那说:你可以这样做:

if(typeof(T) == typeof(Foo)) {
    // foo
} else if (typeof(T) == typeof(Bar)) {
    // bar
} ...

但;这有点遗漏了泛型。

答案 2 :(得分:1)

每当你有if / switch语句,其中代码将根据输入执行不同但产生通用输出,就像你在问题中所做的那样,通常表明你需要考虑做一些重构。

在这种情况下,最好的选择是使用基于接口的设计,并将执行各种报告的逻辑移动到他们自己的类型中。这样您就可以根据需要更好地管理其他报告,而无需触及现有代码。

public interface IReporter {
    void GenerateReport();
}

public class ReporterA : IReporter {
    public void GenerateReport() { /* execute report */} 
}
public class ReporterB : IReporter {
    public void GenerateReport() { /* execute report */} 
}
public class ReporterC : IReporter {
    public void GenerateReport() { /* execute report */} 
}

// The responsibilty of the factory is only to create the correct reporter based on the request
public class ReporterFactory{
    public IReporter CreateReporter(string input){
        /*  the logic here can vary, you can get creative with Attributes 
            and name each report type and use reflection to create the 
            correct report type. You can also use an Enum and use that as an attribute value over
            each Reporter type. There are many ways to handle it.
        */
    }
}

/* your refactored method */
public static void GenerateReport(string report)
{
    /* again, creation pattern could be based on something other than a string. It depends on how you want to differentiate your reporters*/
    var reporter = new ReporterFactory().CreateReporter(report);
    reporter.GenerateReport();
}   

答案 3 :(得分:0)

你可以这样做:

    public static void RunIfEqual<TLeft, TRight>(Action action)
    {
        if (typeof(TLeft) == typeof(TRight))
        {
            action();
        }
    }

    ...

    RunIfEqual<T, ReportA>(()=> ...);
    RunIfEqual<T, ReportB>(()=> ...);
    RunIfEqual<T, ReportC>(()=> ...);

或者更好的方法是,您可以定义一些 ReportGeneratorFactory ,它将选择要用于此类型的生成器并将其返回给您。然后你可以在它上面调用 GenerateReport