Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c# polymorphism + generics design - advice needed

I have a hierarchy of TrendProviders which are used to provide a series of datapoints (trends) from different sources.

I have started with the generic interface:

public interface ITrendProvider<T> where T: TrendResult
{
    IEnumerable<T> GetTrends(); 
}

TrendResult is a result class with the obtained trend data and operation status code:

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; }
}

TrendResultCode is as follows:

public enum TrendResultCode
{
    OK,
    DataParseError,
    NoData,
    UnknownError
}

There are also two types (so far) of more detailed interfaces:

  • IFileTrendProvider - used to obtain trends from any files.

  • IServerTrendProvider - used to obtain trends from remote servers, using FTP for example.

IFileTrendProvider goes like this:

public interface IFileTrendProvider : ITrendProvider<TrendResult>
{
    IFileReader FileReader {get; set}
    FileTrendDiscoveryPattern Pattern {get; set;}  
}

IServerTrendProvider goes like this:

public interface IServerTrendProvider : ITrendProvider<TrendResult>
{
    IClient Client { get; set; }
    Dictionary<string, string[]> RequestedServerTrendIDs { get; set; }
}

The concrete classes that implements the interfaces are as follows:

One of FileTrend type:

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
    }
}

And one of the ServerTrend type:

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
    }
}

Now, what I want to achieve and where I need your help and advice:

The IFileReader introduces its own error codes:

public enum FileReadResultCode
{
    OK,
    FileAlreadyOpen,
    FileNotFound,
    UnknownError
}

IClient also introduces its specific operation error codes:

public enum ClientCode
{
    OK,
    InvalidCredentials,
    ResourceNotFounds,
    UnknownError
}

As both: IFileReader and IClient also returns its own error codes, how could I intruduce them in the TrendResult object returned by GetTrends() method, so that in the end there will be also some information about the "internal" error, not only TrendResult specific error?

I would need some flexible solution - I was thinking about inheriting from TrendResult and create a FileTrendResult and ServerTrendResult for each of concrete providers, and also define a specific error enumerations for both so that they return its own result type, but can it be done in some other way?

like image 277
pitersmx Avatar asked Jun 23 '17 07:06

pitersmx


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr. Stroustroupe.

Is C language easy?

C is a general-purpose language that most programmers learn before moving on to more complex languages. From Unix and Windows to Tic Tac Toe and Photoshop, several of the most commonly used applications today have been built on C. It is easy to learn because: A simple syntax with only 32 keywords.

Is C programming hard?

C is more difficult to learn than JavaScript, but it's a valuable skill to have because most programming languages are actually implemented in C. This is because C is a “machine-level” language. So learning it will teach you how a computer works and will actually make learning new languages in the future easier.


1 Answers

Instead of having a pre-defined list of possible errors in the enumerations (TrendResultCode, FileReadResultCode, ClientCode, ...) you could change the TrendResult class to store a list of exceptions and get rid of the enumerations:

public class TrendResult
{
    // ...    
    // public TrendResultCode Code { get; set; }
    public IEnumerable<Exception> Errors { get; set; }
    // ...
}

This way, you can store the complete information of the error including stack trace and other valuable information (or of several errors if there is more than one problem in a single TrendResult). Even for unexpected errors, you are able to store the details instead of having an unknown error that is hard to track down.

If a TrendResult does not have any items in the enumeration, there are no problems with it. Otherwise, you can put the information to the log.

The implementation follows the Open/Closed principle, so you don't have to change the implementation that handles the TrendResults if there are new conditions that lead to an error.

For your business exceptions, e.g. parsing errors, you should create specific exception types so that you are able to analyze these errors later on based on their type.

like image 99
Markus Avatar answered Oct 11 '22 11:10

Markus