C # can you hide a legacy interface?

I have a set of interfaces and classes that look something like this:

public interface IItem { // interface members } public class Item<T> : IItem { // class members, and IItem implementation } public interface IItemCollection : IEnumerable<IItem> { // This should be enumerable over all the IItems } // We cannot implement both IItemCollection and IEnumerable<TItem> at // the same time, so we need a go between class to implement the // IEnumerable<IItem> interface explicitly: public abstract class ItemCollectionBase : IItemCollection { protected abstract IEnumerator<IItem> GetItems(); IEnumerator<IItem> IEnumerable<IItem>.GetEnumerator() { return GetItems(); } IEnumerator IEnumerable.GetEnumerator() { return GetItems(); } } public class ItemCollection<TKey, TItem> : ItemCollectionBase, IEnumerable<TItem> where TItem : class,IItem,new() { private Dictionary<TKey, TItem> dictionary; protected override GetItems() { return dictionary.Values; } public IEnumerator<TItem> GetEnumerator() { return dictionary.Values; } } 

The problem I am facing is when I try to use Linq on my ItemCollection, it gets confused because there are two IEnumerable interfaces.

The following error message appears:

Type arguments for the 'System.Linq.Enumerable.Where (...) method cannot be taken out of use. Try explicitly specifying type arguments.

Is there a way to hide the “more primitive” IEnumerable <IItem> so that it will always select IEnumerable <TItem> when working with ItemCollection <,>, but still provide an IEnumerable <IItem> interface when working with the IItemCollection interface?


(Since I'm going to post this, I realized that there is a workaround to implement it like this:

 public interface IItemCollection { IEnumerable<IItem> Items { get; } } 

But I still want to know if there is a way to hide the interface.)

+6
source share
2 answers

Perhaps you could achieve what you want with a little composition instead of inheritance:

 public interface IItem { // interface members } public class Item<T> : IItem { // class members, and IItem implementation } public interface IItemCollection { IEnumerable<IItem> GetItems(); } public class ItemCollection<TKey, TItem> : IItemCollection, IEnumerable<TItem> where TItem : class,IItem,new() { private Dictionary<TKey, TItem> dictionary; public IEnumerator<TItem> GetEnumerator() { return dictionary.Values; } public IEnumerable<IItem> GetItems() { return dictionary.Values.Cast<IItem>(); } } 

We can change the IItemCollection so that it returns an IEnumerable<IItem> instead of an IEnumerable<IItem> implementation. Now your concrete class can implement all interfaces and you do not need abstract classes.

+1
source

I think that you are going towards a clever design (if any) that violates the Liskov signature principle

Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.

Somehow smarter than I once said: "Do not make your design smart, KISS."

0
source

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


All Articles