我需要创建一种处理文件的通用方法。根据文件需要执行的操作,应使用特定的类。我使用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();
}
}
答案 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
}
请注意,上面的代码没有静态类型转换,并且它不使用泛型,这在重构后变得不必要。