c#polymorphism +泛型设计 - 需要建议

pit*_*smx 6 c# generics polymorphism

我的层次结构TrendProviders用于提供来自不同来源的一系列数据点(趋势).

我已经开始使用通用接口:

public interface ITrendProvider<T> where T: TrendResult
{
    IEnumerable<T> GetTrends(); 
}
Run Code Online (Sandbox Code Playgroud)

TrendResult 是一个结果类,包含获得的趋势数据和操作状态代码:

public class TrendResult
{
    public TrendResult()
    {
        Points = new Dictionary<DateTimeOffset, decimal>();
    }

    public TrendResultCode Code { get; set; }
    public string Name { get; set; }
    public string Identifier { get; set; }
    public Dictionary<DateTimeOffset, decimal> Points { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

TrendResultCode 如下:

public enum TrendResultCode
{
    OK,
    DataParseError,
    NoData,
    UnknownError
}
Run Code Online (Sandbox Code Playgroud)

还有两种类型(到目前为止)更详细的接口:

  • IFileTrendProvider - 用于从任何文件中获取趋势.

  • IServerTrendProvider - 用于从远程服务器获取趋势,例如使用FTP.

IFileTrendProvider 是这样的:

public interface IFileTrendProvider : ITrendProvider<TrendResult>
{
    IFileReader FileReader {get; set}
    FileTrendDiscoveryPattern Pattern {get; set;}  
}
Run Code Online (Sandbox Code Playgroud)

IServerTrendProvider 是这样的:

public interface IServerTrendProvider : ITrendProvider<TrendResult>
{
    IClient Client { get; set; }
    Dictionary<string, string[]> RequestedServerTrendIDs { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

实现接口的具体类如下:

其中FileTrend一种:

public class GenericFileTrendProvider : IFileTrendProvider<TrendResult>
{
    public GenericFileTrendProvider() { }

    public IFileReader FileReader {get; set}
    public FileTrendDiscoveryPattern Pattern {get; set;}  

    public IEnumerable<TrendResult> GetTrends()
    {
       // Some code to obtain trends from file using FileReader
    }
}
Run Code Online (Sandbox Code Playgroud)

其中一种ServerTrend类型:

public class ServerATrendProvider : IServerTrendProvider<TrendResult>
{
    public ServerATrendProvider () { }

    public IClient Client { get; set; }
    public Dictionary<string, string[]> RequestedServerTrendIDs { get; set;}

    public IEnumerable<TrendResult> GetTrends()
    {
       // Some code to obtain trends from remote server using Client
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,我想要实现的目标以及我需要您的帮助和建议的地方:

IFileReader推出了自己的错误代码:

public enum FileReadResultCode
{
    OK,
    FileAlreadyOpen,
    FileNotFound,
    UnknownError
}
Run Code Online (Sandbox Code Playgroud)

IClient 还介绍了其具体的操作错误代码:

public enum ClientCode
{
    OK,
    InvalidCredentials,
    ResourceNotFounds,
    UnknownError
}
Run Code Online (Sandbox Code Playgroud)

作为两者:IFileReader并且IClient还返回自己的错误代码,我怎么能在方法TrendResult返回的对象中引入它们GetTrends(),这样最终还会有一些关于"内部"错误的信息,而不仅仅是TrendResult特定的错误?

我需要一些灵活的解决方案-我在想继承TrendResult和创造FileTrendResult,并ServerTrendResult为每一个具体的供应商,同时也定义了两种特定的错误枚举,使他们返回自己的结果类型,但它可以在一些其他的方式来完成?

Mar*_*kus 3

您可以更改类以存储异常列表并删除枚举,而不是在枚举中预先定义可能的错误列表(TrendResultCodeFileReadResultCode、 、 ...):ClientCodeTrendResult

public class TrendResult
{
    // ...    
    // public TrendResultCode Code { get; set; }
    public IEnumerable<Exception> Errors { get; set; }
    // ...
}
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您可以存储错误的完整信息,包括堆栈跟踪和其他有价值的信息(如果单个问题中有多个问题,则可以存储多个错误的信息TrendResult)。即使对于意外错误,您也可以存储详细信息,而不是出现难以追踪的未知错误。

如果 a 的 TrendResult枚举中没有任何项目,则没有问题。否则,您可以将信息写入日志。

该实现遵循开放/关闭原则,因此您不必更改处理TrendResults新情况导致错误的实现。

对于您的业务异常,例如解析错误,您应该创建特定的异常类型,以便稍后能够根据错误的类型来分析这些错误。