在C#中实现与泛型类型的接口的类的工厂?

时间:2014-08-06 15:08:04

标签: c# generics

我需要创建一种处理文件的通用方法。根据文件需要执行的操作,应使用特定的类。我使用ASP和C#。文件上传,我分析文件,创建分析结果对象,并根据该对象向用户显示分析结果。用户读取分析结果并继续(单击按钮)或不进行。如果他这样做,我会采用该分析结果对象并基于它执行操作(处理)。我向用户显示处理结果。

根据某些查询参数(为简单起见),文件应由不同的类处理。处理器需要特定于分析器具体实现的分析结果(分析一个文件的结果可能包含自定义类的列表,不同文件分析的结果可能包含其他特定字段)。处理器需要这些特定于实现的细节来完成它的工作。

我试图创建一般项目但是陷入困境。

工厂中的magicId是一个查询参数,指定应该使用哪个类来解析/分析文件。

有没有办法创建一个类的工作工厂,它们都实现了通用类型的接口?

abstract class AnalysisResult
{
}

interface IAnalyzer<TAnalysisResult>
    where TAnalysisResult : AnalysisResult
{
    TAnalysisResult PerformAction(string input);
}

class ConcreteAnalysisResult : AnalysisResult {
    public int SpecificProperty { get; set; }
}

class ConcreteAnalyzer : IAnalyzer<ConcreteAnalysisResult>
{
    public ConcreteAnalysisResult PerformAction(string input)
    {
        return new ConcreteAnalysisResult() { SpecificProperty = input.Length };
    }
}

class AnAnalyzerFactory
{
    IAnalyzer<AnalysisResult> CreateByMagicId(int magicId)
    {
        return new ConcreteAnalyzer();
    }
}

2 个答案:

答案 0 :(得分:4)

TAnalysisResult声明为协变。有关详细信息,请查看Covariance and Contravariance

interface IAnalyzer<out TAnalysisResult> // note out keyword
    where TAnalysisResult : AnalysisResult
{
    TAnalysisResult PerformAction(string input);
}

答案 1 :(得分:2)

尽管您可以使用类型协方差来修复代码,但代码中仍会存在根据分析器的具体类型进行分派的位置。这不是最理想的,因为泛型的使用隐藏了以后需要“取消隐藏”的东西(例如,到达SpecificProperty属性)。

我认为更好的方法是以与visitor pattern类似的方式反转对分析结果接收者的控制,如下所示:

// The following removes generics from your code
abstract class AnalysisResult {
}

interface IAnalyzer {
    AnalysisResult PerformAction(string input);
}

class ConcreteAnalysisResult : AnalysisResult {
    public int SpecificProperty { get; set; }
}

class ConcreteAnalyzer : IAnalyzer {
    public AnalysisResult PerformAction(string input) {
        return new ConcreteAnalysisResult() { SpecificProperty = input.Length };
    }
}
// Here is the magic that lets you process results of specific types without generics
public static void main(string[] args) {
    var analyzer = new ConcreteAnalyzer();
    dynamic res = analyzer.PerformAction(input);
    ProcessResult(res); // This gets dispatched dynamically to the correct overload
}
private static void ProcessResult(ConcreteAnalysisResult cr) {
    Console.WriteLine(cr.SpecificProperty);
}
private static void ProcessResult(SomeOtherConcreteAnalysisResult cr) {
    Console.WriteLine(cr.AnoterhSpecificProperty);
}
private static void ProcessResult(AnalysisResult cr) {
    // Throw an error: unexpected result type
}

请注意,上面的代码没有静态类型转换,并且它不使用泛型,这在重构后变得不必要。