C#——注入一个IDictionary<;A、 IList<;B>&燃气轮机;
我希望将IDictionary实例注入到类中,但希望控制所使用的IList的实现。我用泛型做这件事的方法让人觉得很笨拙。这会使类定义变得笨拙,如果有多个类似的对象我想注入,情况只会变得更糟C#——注入一个IDictionary<;A、 IList<;B>&燃气轮机;,c#,generics,dependency-injection,C#,Generics,Dependency Injection,我希望将IDictionary实例注入到类中,但希望控制所使用的IList的实现。我用泛型做这件事的方法让人觉得很笨拙。这会使类定义变得笨拙,如果有多个类似的对象我想注入,情况只会变得更糟 public class Lookup<T1, T2, T3> where T2 : IList<T3>, new() { private IDictionary<T1, T2> _underlyingDict; public Lookup(IDictio
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);
}
}
公共类查找,其中T2:IList,new()
{
私人词典;
公共查找(IDictionary dict)
{
_基础dict=dict;
}
公共T2 Get(T1键)
{
返回_underyingdict[键];
}
公共无效添加(T1键,T3值)
{
如果(!_underyingdict.ContainsKey(键))
{
_underyingdict[key]=新的T2();
}
_underyingdict[key].Add(value);
}
}
这种方法是否存在任何问题,是否有更干净的解决方案?如果您很高兴构造函数的调用者仍然有对您的集合所基于的词典的引用,那么对我来说这看起来没问题。我个人会将
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);
}
您可能还想考虑从<代码>查找> /代码>重命名该类型,因为它与<代码> St.LINQ.Loope冲突。显然,您可能正在创建自己的替换
Lookup
类,这将解释这一点。。。但是如果客户端有可能同时使用你的类和“正常”LINQ,我会考虑重命名。< /P>
另一个不需要额外类型参数的选项是接受委托以创建相关列表类型的新实例:
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;
}
...
}
公共类查找
{
私人词典;
私有函数列表创建者;
公共查找(IDictionary dict,
Func listCreator)
{
_基础dict=dict;
_listCreator=listCreator;
}
...
}
然后,在您以前有
newt2()
的地方,只需调用\u listCreator()
我更喜欢创建从泛型基类继承的特定类:
public class FooLookup : Lookup<int, List<Foo>, Foo>
{
public FooLookup(IDictionary<int, List<Foo>> dict)
: base(dict)
{
}
}
公共类傻瓜库:查找
{
公共傻瓜书(IDictionary 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);
var dictionary=newdictionary();
傻瓜书=新的傻瓜书(字典);
查找=新查找(字典);
我不喜欢在代码中使用带有T1、T2、T3、T4的类的主要原因是人类的思维——一般人一次可以在头脑中记住大约7(+/-2)件事情。因此,创建T1、T2、T3、T4将占用4的东西,留下3的业务逻辑。 < P>尽管有可能做你正在做的事情,但你可能要考虑这一点: 如果您正在进行依赖项注入,通常不会注入基元类型。这包括基本收藏。依赖注入在注入长寿命的单例作用域对象时效果最好,类似于DDD中的服务
您可能想考虑使用一种类型来包含这个代码> IDICORIGION/CODE >试图表示的思想。这个物体是用来做什么的?它如何与系统中的其他对象交互?这些问题的答案可能会导致一个复杂的类型,可能混合了一些功能。也许这是一个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
}
公共类存储库
{
专用词典m_存储库;
FooRepository()
{
m_repository=新字典();
}
公共添加(int键,IList值)
{
m_repository.Add(key,value);
}
//其他公开披露的方法
}
<> P>您可能会考虑这样做的原因是使用<代码> IDICORIGION/CODE >的任何东西都可能获得比它需要的更多的方法,并且您希望遵循良好的数据封装实践,以允许该对象的用户只访问他们需要的那些东西。为什么不从LINQ使用<代码> ToLookup < /代码>?考虑泛型PARAMs的更好名称。好点LePiP-这有点像个玩具例子。我实际上是在写一个双向查找时遇到它,我想知道“如果……”是的,这会让界面变得更整洁。你能给出一个你想要实现的具体例子吗。你注入的到底是什么,以及如何使用它。这可能会给我一些指导,让我写一个对你有用的答案。如果您愿意,可以更新您的问题。谢谢Jon。在这种情况下,它不是替换查找;我在玩双向查找,这是一个精简版。我更喜欢委托版本,因为委托的添加将所有注入保持在一起,而不是将其涂抹在ctor和泛型上。+1:您的类型应该表示问题域模型中的逻辑实体。正如OP所指出的,你的实体很可能根本不是一本字典:它是一组,比如说,顾客,对某种外部刺激做出反应。这也可以归结为灵长类动物。小部件的价格可能由十进制值表示,但它根本不是十进制值。它是一个名为price的实体,具有特定的[内部]表示、一组约束和一组允许的操作。