2013-09-28 2 views
2

Скажем, у меня есть следующие модели:Можете ли вы удовлетворить интерфейс с IEnumerable <T> с помощью списка <T>?

public interface IProduct 
{ 
    IEnumerable<Ingredient> Ingredients { get; set; } 
} 

public class Product : IProduct 
{ 
    public IEnumerable<Ingredient> Ingredients { get; set; } 
} 

public class Ingredient 
{ 
} 

Но я хочу Ingredients, чтобы быть List<Ingredient> вместо IEnumerable<Ingredient>

Есть ли способ моделировать интерфейс принимать IEnumerable<T> и List<T>?

Я пробовал следующее. Но, конечно, синтаксис не поддерживает это и не видит TEnumerable<Ingredient> в качестве общего параметра.

public interface IProduct<TEnumerable<Ingredient>> 
    where TEnumerable<Ingredient> : IEnumerable<Ingredient> 
{ 
    TEnumerable<Ingredient> Ingredients { get; set; } 
} 

public class Product : IProduct 
{ 
    public List<Ingredient> Ingredients { get; set; } 
} 

public class Ingredient 
{ 
} 

Я понимаю, что это не очень практично, но я просто смотрю на это с любопытством.

+0

Помните LSP. Причина, по которой вы не можете сделать это напрямую, заключается в том, что вы не могли сказать, назовите 'new Product(). Ingredients = Enumerable.Empty ()'. То есть подкласс будет нарушать его интерфейс, который говорит '(новый продукт() как IProduct) .Ingredients = Enumerable.Empty ()' должен быть действительным. – millimoose

ответ

4

Ваш синтаксис откусил:

  • Вы не можете объявить параметр типа в общем виде, как это
  • Ваш Product тип должен определить тип аргумента, когда он говорит, как он реализует IProduct<TEnumerable>

Так это справедливо:

public interface IProduct<TEnumerable> 
    where TEnumerable : IEnumerable<Ingredient> 
{ 
    TEnumerable Ingredients { get; set; } 
} 

public class Product : IProduct<List<Ingredient>> 
{ 
    public List<Ingredient> Ingredients { get; set; } 
} 

Это может быть полезно , но по крайней мере это действует ...

+0

Возможно, стоит упомянуть, что вы фактически не можете присваивать экземпляр 'Product' переменной« IProduct > », что делает эту конструкцию несколько менее полезной, чем кажется. – millimoose

+0

Hah! Я вижу, где я ошибся. Спасибо, Джон, и, как всегда, ты удивительно быстро. Я еще ничего не ожидал увидеть еще несколько минут. – Khan

+0

@millimoose Я уже вижу это совершенно бесполезным, просто играя с синтаксисом :) – Khan

2

заинтересованы в том, чтобы ваш конкретную реализацию IProduct использования List<> внутренне, или заинтересованы в разоблачении List<> в некоторых реализациях и IEnumerable в другой ты?

Если это первое, что вам не нужно делать ничего - List<T> орудия IEnumerable<T>, так что если Product имеет внутреннюю List<Ingredient>, вы можете просто вернуть его как IEnumerable<Ingredient>:

public class Product : IProduct 
{ 
    private List<Ingredient> _ingredients; 
    public IEnumerable<Ingredient> Ingredients { get { return _ingredients; } } 
} 

Если, однако, вы «Заинтересовался вторым вариантом (который отвечает Джон Скит для вас), я должен спросить вас, почему вы хотите этого, поскольку это в основном затрудняет использование интерфейса - вместо того, чтобы иметь единый контракт, что все вызывающие абоненты, у вас есть общий метаинтерфейс, который по-разному используется разными абонентами. Это интересная концепция, но кажется излишним, если все, что вы хотите сделать, это заменить IEnumerable на IList.

Смежные вопросы