Как бороться с ковариацией при возврате коллекции в C #?

У меня проблема с возвратной коллекцией и ковариацией, и мне было интересно, есть ли у кого-то лучшее решение.

Сценарий это:

У меня есть 2 версии реализации, и я хотел бы сохранить реализацию версии полностью отдельными (хотя у них может быть такая же логика). В реализации я хотел бы вернуть список предметов и, следовательно, в интерфейсе, я бы вернул список интерфейса элемента. Однако в фактической реализации интерфейса я хотел бы вернуть конкретный объект элемента. В коде это выглядит что-то вроде этого.

interface IItem
{
    // some properties here
}

interface IResult
{
    IList<IItem> Items { get; }
}

Затем будут 2 пространства имен, которые имеют бетонную реализацию этих интерфейсов. Например,

пространство имен версия1

class Item : IItem

class Result : IResult
{
    public List<Item> Items
    {
        get { // get the list from somewhere }
    }

    IList<IItem> IResult.Items
    {
        get
        {
            // due to covariance, i have to convert it
            return this.Items.ToList<IItem>();
        }
    }
}

будет другая реализация того же вещей под пространством имен версии2.

Чтобы создать эти объекты, будет завод, которая возьмет версию и создает соответствующий тип бетона по мере необходимости.

Если вызывающий абонент знает точную версию и делает следующее, код работает нормально

Version1.Result result = new Version1.Result();
result.Items.Add(//something);

, однако, я хотел бы, чтобы пользователь мог сделать что-то вроде этого.

IResult result = // create from factory
result.Items.Add(//something);

Но, потому что он был преобразован в другой список, добавление ничего не сделает, потому что элемент не будет добавлен обратно к исходному объекту результата.

Я могу подумать о нескольких решениях, таких как:

  1. Я мог бы синхронизировать два списка, но это кажется дополнительной работой
  2. возврата INUMERABLABLABLABLABLE вместо iList и добавить метод для создания / удаления коллекций
  3. Создайте пользовательскую коллекцию, которая принимает TConcrete и Tinterface

Я понимаю, почему это происходит (из-за типового безопасного и всех), но ни одно из обходных путей я думаю, кажется очень элегантным. У кого-нибудь есть лучшие решения или предложения?

заранее спасибо!

Обновление

После этого, я думаю, что я могу сделать следующее:

public interface ICustomCollection<TInterface> : ICollection<TInterface>
{
}

public class CustomCollection<TConcrete, TInterface> : ICustomCollection<TInterface> where TConcrete : class, TInterface
{
    public void Add(TConcrete item)
    {
        // do add
    }

    void ICustomCollection<TInterface>.Add(TInterface item)
    {
        // validate that item is TConcrete and add to the collection.
        // otherwise throw exception indicating that the add is not allowed due to incompatible type
    }

    // rest of the implementation
}

Тогда я могу иметь

interface IResult
{
    ICustomCollection<IItem> Items { get; }
}

then for implementation, I will have

class Result : IResult
{
    public CustomCollection<Item, IItem> Items { get; }

    ICustomCollection<TItem> IResult.Items
    {
        get { return this.Items; }
    }
}

таким образом, если вызывающий абонент доступа к классу результата, он пройдет через CustomCollection. Добавить (элемент TConcrete), который уже запирается. Если вызывающий абонент доступа к интерфейсу Iresult, он пройдет через CustomCollection.Add (элемент Tinterface), а проверка произойдет и убедится, что тип на самом деле TConcrete.

Я попробую посмотреть, будет ли это работать.

9
задан Khronos 11 September 2011 в 17:49
поделиться