在c#中实现泛型接口的类工厂

本文关键字:工厂 泛型接口 实现 | 更新日期: 2023-09-27 18:16:58

我需要创建一个处理文件的通用方法。根据需要对文件执行的操作,应该使用特定的类。我使用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();
    }
}

在c#中实现泛型接口的类工厂

声明TAnalysisResult为协变。有关详细信息,您可以查看协方差和逆变

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

虽然您可以通过使用类型协方差来修复代码,但是在代码中仍有一个地方需要根据分析器的具体类型进行分派。这是次优的,因为使用泛型隐藏了一些稍后需要"解除隐藏"的东西(例如,为了获得SpecificProperty属性)。

我认为更好的方法是以类似于访问者模式的方式反转对分析结果接收者的控制,像这样:
// 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
}

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