gpt4 book ai didi

c# - 我怎样才能把这个类写得完全通用,并根据一个请求返回不同的响应?

转载 作者:行者123 更新时间:2023-11-30 14:53:11 26 4
gpt4 key购买 nike

我被要求为应用程序创建一系列报告,一如既往,我正在寻找减少代码编写量的方法。我已经开始尝试提出请求单个报告的最简单方法。这是我的想象:

var response = ReportGenerator.Generate(Reports.Report1);
//Reports would be an enum type with all of the available reports.

当我尝试设计它时,问题就出现了。每个报告都有不同的输入和输出。输入是报告所基于的实体(或多个实体),输出是持有已处理数据的 DTO。

支持这个,我创建了这个:

// The interface for every report
public interface IReport<INPUT, OUTPUT>
{
public OUTPUT GenerateReport(INPUT input);
}

// A base class for every report to share a few methods
public abstract class BaseReport<INPUT, OUTPUT> : IReport<INPUT, OUTPUT>
{
// The method required by the IReport interface
public OUTPUT GenerateReport(INPUT input)
{
return Process(input);
}

// An abstract method to be implemented by every concrete report
protected abstract OUTPUT Process(INPUT input);
}

public class ConcreteReport : BaseReport<SomeEntity, SomeDto>
{
protected override SomeDto Process(SomeEntity input)
{
return default(SomeDto);
}
}

起初我考虑让每个具体报告指定负责确定其自身输入的逻辑。我很快发现这会使我的类(class)更难测试。通过让报告请求 INPUT 通用类型的实例,我可以模拟该对象并测试报告。

因此,我需要某种类来将报告(枚举值之一)绑定(bind)到负责生成报告的具体报告类。我正在尝试使用类似于依赖注入(inject)容器的方法。这是我在编写时遇到的问题。

我将在下面写下我的评论,解释我发现的问题(它在语法上不应该是正确的 - 它只是一个 stub ,因为我的问题正是这个类的实现):

public class ReportGenerator
{
// This would be the dictionary responsible for tying an enum value from the Report with one of the concrete reports.
// My first problem is that I need to make sure that the types associated with the enum values are instances of the BaseReport class.
private readonly Dictionary<Reports, ?> registeredReports;

public ReportGenerator()
{
// On the constructor the dictionary would be instantiated...
registeredReports = new Dictionary<Reports, ?>();

// and the types would be registered as if in a dependency injection container.
// Register(Reports.Report1, ConcreteReport);
// Register(Reports.Report2, ConcreteReport2);
}

// Below is the most basic version of the registration method I could come up with before arriving at the problems within the method GenerateReport.

// T repository - this would be the type of the class responsible for obtainning the input to generate the report
// Func<T, INPUT> expression - this would be the expression that should be used to obtain the input object

public void Register<T, INPUT>(Reports report, Type reportConcreteType, T repository, Func<T, INPUT> expression)
{
// This would basically add the data into the dictionary, but I'm not sure about the syntax
// because I'm not sure how to hold that information so that it can be used later to generate the report

// Also, I should point that I prefer to hold the types and not instances of the report and repository classes.
// My plan is to use reflection to instantiate them on demand.
}

// Based on the registration, I would then need a generic way to obtain a report.
// This would the method that I imagined at first to be called like this:
// var response = ReportGenerator.Generate(Reports.Report1);

public OUTPUT Generate(Reports report)
{
// This surely does not work. There is no way to have this method signature to request only the enum value
// and return a generic type. But how can I do it? How can I tie all these things and make it work?
}
}

我可以看到它与报告接口(interface)或抽象类无关,但我无法弄清楚实现。

最佳答案

我不确定是否可以使用枚举实现这种行为,因此我可以向您提出以下解决方案:

  1. 使用一些标识符通用类(接口(interface))代替枚举值。要将其用作字典中的键,您还必须具有此类的一些非通用基础。
  2. 有一些带有上述标识符类的静态类作为特定的静态属性。
  3. 使用静态类属性的值作为 ReportGenerator 中的键类。

这里是必需的接口(interface):

public interface IReportIdentifier
{

}

public interface IReportIdentifier<TInput, TOutput> : IReportIdentifier
{

}

public interface IReport<TInput, TOutput>
{
TOutput Generate(TInput input);
}

这是静态“枚举”类:

public static class Reports
{
public static IReportIdentifier<String, Int32> A
{
get { return null;}
}

public static IReportIdentifier<Object, Guid> B
{
get { return null; }
}
}

这是 ReportGenerator 类:

public class ReportGenerator
{
IDictionary<IReportIdentifier, Object> reportProducers = new Dictionary<IReportIdentifier, Object>();

public void Register<TInput, TOutput>(IReportIdentifier<TInput, TOutput> identifier, IReport<TInput, TOutput> reportProducer)
{
reportProducers.Add(identifier, reportProducer);
}

public TOutput Generate<TInput, TOutput>(IReportIdentifier<TInput, TOutput> identifier, TInput input)
{
// Safely cast because it is this class's invariant.
var producer = (IReport<TInput, TOutput>)reportProducers[identifier];
return producer.Generate(input);
}
}

如您所见,我们使用了 cast 但它隐藏在 Generate 中方法,如果我们的 Register方法是对 reportProducers 的唯一访问点字典此转换不会失败。

还有@CoderDennis pointed :

Then you could always use T4 to generate that static class and its static properties and could even create an extension method that returns the proper IReportIdentifier from your enum.

关于c# - 我怎样才能把这个类写得完全通用,并根据一个请求返回不同的响应?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30057636/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com