简体   繁体   中英

C# can you hide an inherited 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 run into is when I try use Linq on my ItemCollection, it gets confused because there are two IEnumerable interfaces.

I get the following error message:

The type arguments for method 'System.Linq.Enumerable.Where(...) cannot be inferred from the usage. Try specifying the type arguments explicitly.

Is there any way to hide the "more primitive" IEnumerable<IItem> interface so it will always choose the IEnumerable<TItem> when dealing with the ItemCollection<,>, but still provide the IEnumerable<IItem> interface when dealing with IItemCollection interface?


(As I'm about to post this, I realized that there's a workaround, to implement it like this:

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

But I still want to know if there's a way to hide an interface.)

Perhaps you could achieve what you want with a little bit of 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 IItemCollection so that it returns an IEnumerable<IItem> instead of implementing IEnumerable<IItem> . Now your concrete class can implement all interfaces and you don't need abstract classes.

I think you are heading to a clever design (if there is one) which violates Liskov substitution principle

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

As someone smarter than me once said "don't make your design clever, KISS."

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM