C # - внедрение IDictionary - PullRequest
       4

C # - внедрение IDictionary

1 голос
/ 18 января 2011

Я хотел бы добавить экземпляр IDictionary > в класс, но хочу сохранить контроль над реализацией используемого IList . То, как я это делаю - с помощью дженериков - кажется неуклюжим. Это делает определение класса громоздким, и будет только хуже, если будет несколько похожих объектов, которые я хотел бы добавить.

public class Lookup<T1, T2, T3> where T2 : IList<T3>, new()
{
    private IDictionary<T1, T2> _underlyingDict;

    public Lookup(IDictionary<T1, T2> dict)
    {
        _underlyingDict = dict;
    }

    public T2 Get(T1 key)
    {
        return _underlyingDict[key];
    }

    public void Add(T1 key, T3 value)
    {
        if (!_underlyingDict.ContainsKey(key))
        {
            _underlyingDict[key] = new T2();
        }
        _underlyingDict[key].Add(value);
    }
}

Есть ли проблемы с этим подходом, и есть ли более чистое решение?

Ответы [ 3 ]

2 голосов
/ 19 января 2011

Хотя можно делать то, что вы делаете, вы можете подумать об этом:

Если вы делаете внедрение зависимостей, вы обычно не внедряете примитивные типы.Это включает в себя основные коллекции.Внедрение зависимостей лучше всего работает при внедрении долгоживущих объектов с одноэлементной областью, схожих с сервисами в DDD-говорящих.

Возможно, вы захотите рассмотреть создание типа, чтобы охватить идею, которую этот IDictionary<int, IList<B>> пытается представить,Для чего используется этот объект?Как это взаимодействует с другими объектами в вашей системе?Ответы на эти вопросы могут привести к сложному типу, возможно, со смешанной функциональностью. Может быть, это FooRepository, и вам нужны только определенные методы полного объекта IDictionary, чтобы вы получили что-то вроде этого:

public class FooRepository<T>
{
    private IDictionary<int, IList<T>> m_repository;

    FooRepository()
    {
        m_repository = new Dictionary<int, List<T>>();
    }

    public Add(int key, IList<T> value)
    {
        m_repository.Add(key, value);
    }

    // other public methods to expose
}

Причина, по которой вы могли бы подумать об этом, заключается в том, что все, что использует IDictionary<int, List<T>>, вероятно, имеет доступ к гораздо большему количеству методов, чем необходимо, и вы хотите следовать хорошим методам инкапсуляции данных, чтобы потребители этого объекта могли получать доступ только к тем вещам, которые онитребуется.

1 голос
/ 18 января 2011

Это выглядит нормально для меня, если вы рады, что вызывающая сторона конструктора все еще имеет ссылку на словарь, на котором основана ваша коллекция. Я бы лично изменил метод Add, чтобы использовать меньше поисков по словарю:

public void Add(T1 key, T3 value)
{
    T2 list;
    if (!_underlyingDict.TryGetValue(key, out list))
    {
        list = new T2();
        _underlyingDict[key] = list;
    }
    list.Add(value);
}

Вы также можете рассмотреть возможность переименования типа из Lookup, учитывая, что он конфликтует с System.Linq.Lookup. Очевидно, что вы можете создать свой собственный класс replace Lookup, который бы это объяснил ... но если есть вероятность, что клиенты будут использовать и ваш класс, и "обычный" LINQ, буду рассматривать переименование.


Другой вариант, который устраняет необходимость в дополнительном параметре типа, - это принять делегата для создания нового экземпляра соответствующего типа списка:

public class Lookup<T1, T2>
{
    private IDictionary<T1, IList<T2>> _underlyingDict;
    private Func<IList<T2>> _listCreator;

    public Lookup(IDictionary<T1, IList<T2>> dict,
                  Func<IList<T2>> listCreator)
    {
        _underlyingDict = dict;
        _listCreator = listCreator;
    }

    ...
}

тогда, где у вас раньше был new T2(), просто позвоните _listCreator().

0 голосов
/ 18 января 2011

Я предпочитаю создавать определенные классы, унаследованные от базовых базовых классов:

public class FooLookup : Lookup<int, List<Foo>, Foo>
{
    public FooLookup(IDictionary<int, List<Foo>> dict)
        : base(dict)
    {            
    }
}

Это делает код намного чище.Сравните:

var dictionary = new Dictionary<int, List<Foo>>();

FooLookup fooLookup = new FooLookup(dictionary);
Lookup<int, List<Foo>, Foo> lookup = new Lookup<int, List<Foo>, Foo>(dictionary);

Основная причина, почему я не люблю использовать классы с T1, T2, T3, T4 в коде, - это человеческий разум - среднестатистические люди могут хранить около 7 (+/- 2) вещейих голова за один раз.Таким образом, создание T1, T2, T3, T4 займет 4 из этих вещей, оставляя 3 бизнес-логике.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...