Interface returning derived types

class Result { public string Data { get; set; } } interface IRepository { Result[] Search(string data); } 

I have a pretty general interface that searches for "something" and returns a Result . The IRepository interface can be implemented by several classes, each of which returns its own result with its own unique metadata. For example, I might have a DiskRepository that searches for data on disk:

 class DiskResult : Result { public int FileSize { get; set; } public DateTime LastModifiedDate { get; set; } } class DiskRepository : IRepository { public Result[] Search(string data) { // ... DiskResult[] results = GetDataFromSomewhere(); return results; } } 

DiskResult provides additional information about the result specific to DiskRespository . If I created another class that implements IRepository , this particular implementation may have its own set of metadata that is unique to this class.

In the end, I would like my search controller to look like this:

 class SearchController { private IRepository[] _repositories; public SearchController(IRepository[] repositories) { _repositories = repositories; } public void Display(string data) { Result[] results = _repositories.Search(data); // Display results } } 

I can easily display the Data property in my Result class, but is there a good template for displaying metadata for each class that comes from Result ? I could have a bunch of if to check if the class is a type, but it feels a little awkward. Is there a better way to do what I'm trying to achieve?

+4
source share
4 answers

One comment correctly states that adding virtual Display () to your Result class violates the principle of single responsibility. That's right.

Wipe your question here: because you want to do things like this:

 private IRepository[] _repositories; 

... there is no way to avoid type checking at runtime. The compiler has no idea which return type-result-from-result will be returned. All he knows is that your repository returns the object obtained from the result.

On the other hand, if you use generics:

 interface IRepository<T> where T : Result { T[] Search(string data); } 

... at compile time, you will find out what type of Result subclass you have in mind, thereby eliminating the need for type checking and the long string of "if" statements that follow from the first approach.

If you can use generics, then you can do things like this:

 interface IResultDisplayService<T> where T : Result { void Display(T result); } 

So, I suppose, my question is: is it necessary to store an array of these repositories? What is the real world use case for?

+1
source

I would not use the repository interface for this, but create a new one:

 public interface ISearchProvider { IEnumerable<SearchResultItem> Search(string keyword); } public interface ISearchResultItem { string Title {get; } string Description {get; } NameValueCollection Metadata {get; } } 

The name and description should be sufficient for 90% of search cases. For example, DiskResult may include a folder, etc. In the Description property. Metadata can be displayed in a tooltip or in the form of information.

If this is not enough, I would also create a visualization interface:

 public interface ISearchResultRenderer { bool IsValidFor(Type type); void Render(Stream stream); } 

And do an implementation of DiskResultHtmlRenderer that goes through the metadata and structures them correctly.

+1
source

You can make the IRepository common interface, for example:

 interface IRepository<T> { T[] Search(string data); } 
0
source

The result class may have a virtual method that displays the results. Your child class can override and can give its own implementation. By doing this when calling the Display method, your Result object will call the appropriate method to display.

Something like that

 class Result { public virtual void Display() { //Your Code } //Your Code } class DiskResult : Result { public override void Display() { //Your Code } //Your Code } 

Your Display method

 public void Display(string data) { Result[] results = _repositories.Search(data); // Display results foreach(var result in results) { result.Display(); } } 

Hope this helps you.

0
source

Source: https://habr.com/ru/post/1398528/


All Articles