我想注入一个IDictionary< A,IList< B>>的实例。进入一个类,但希望继续控制IList< B>的实现用过的。我做这件事的方式 - 使用泛型 - 感觉很笨拙。它使类定义变得笨拙,并且只有在我想要注入多个类似对象时才会变得更糟。
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);
}
}
这种方法有什么问题,是否有更清洁的解决方案?
答案 0 :(得分:2)
虽然可以做你正在做的事情,但你可能想要考虑这个:
如果您正在进行依赖注入,则通常不会注入基本类型。这包括基本馆藏。注入长寿命单例范围的对象时,依赖注入最有效,类似于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 :(得分:1)
对我而言,如果您对构造函数的调用者仍然对您的集合所基于的字典的引用感到高兴,这对我来说没问题。我个人会更改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
重命名该类型。显然,您可能正在创建自己的替换 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()
。
答案 2 :(得分:0)
我更喜欢创建从泛型基类继承的特定类:
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个业务逻辑。