好吧,我想为IDictionary和IReadOnlyDictionary接口编写一个扩展方法:
public static TValue? GetNullable<TKey,TValue>(this IReadOnlyDictionary<TKey,TValue> dictionary,TKey key) where TValue : struct { return dictionary.ContainsKey(key) ? (TValue?)dictionary[key] : null; } public static TValue? GetNullable<TKey,TValue>(this IDictionary<TKey,TKey key) where TValue : struct { return dictionary.ContainsKey(key) ? (TValue?)dictionary[key] : null; }
但是当我将它用于实现两个接口的类(例如Dictionary< Tkey,TValue>)时,我得到了“模糊的调用”.我不想输入var value = myDic.GetNullable< IReadOnlyDictionary< MyKeyType,MyValueType>>(key),我希望它只是var value = myDic.GetNullable(key).
这可能吗?
解决方法
public static TValue? GetNullableKey<TKey,TValue>(this IEnumerable<KeyValuePair<TKey,TValue>> dictionary,TKey,key) where TValue : struct { // Your code here. // Per @nmclean: to reap performance benefits of dictionary lookup,try to cast // dictionary to the expected dictionary type,e.g. IDictionary<K,V> or // IReadOnlyDictionary<K,V>. Thanks for that nmclean! }
IDictionary< TKey,TValue>和IReadOnlyDictionary< TKey,TValue>继承自IEnumerable< KeyValuePair< TKey,TValue>>.
HTH.
更新:回答您的评论问题
如果你不需要调用只出现在一个接口或另一个接口上的方法(即你只调用IEnumerable< KeyValuePair< TKey,TValue>>)上存在的方法,那么不,你不需要那个码.
如果你确实需要在IDictionary< TKey,TValue>上调用方法.或IReadOnlyDictionary< TKey,TValue>在公共基础接口上不存在的接口,然后是,您需要查看您的对象是否是其中一个,以了解哪些方法可以被调用.
更新:您可能(很可能)不应该使用此解决方案
因此,从技术上讲,这个解决方案在回答OP的问题时是正确的,如上所述.然而,这真的不是一个好主意,正如其他人在下面评论过的那样,并且我已经承认这些评论是正确的.
首先,字典/地图的整个点是O(1)(恒定时间)查找.通过使用上面的解决方案,您现在已将O(1)操作转换为O(n)(线性时间)操作.如果你的词典中有1,000,000个项目,那么查找关键值需要多达100万次(如果你真的不走运).这可能会对性能产生重大影响.
一本小字典怎么样?那么问题就变成了,你真的需要一本字典吗?列表会更好吗?或许是一个更好的问题:你在哪里开始注意到使用O(n)而不是O(1)查找的性能影响以及你期望执行这样的查找的频率是多少?
最后,OP的情况是一个实现IReadOnlyDictionary< TKey,TValue>的对象.和IDictionary< TKey,TValue>是,奇怪,作为IDictionary< TKey,TValue>的行为是IReadOnlyDictionary< TKey,TValue>行为的超集.和标准词典< TKey,TValue> class已经实现了这两个接口.因此,如果OP(我假设,专门)类型继承自Dictionary< TKey,TValue>相反,当需要只读功能时,类型可以简单地转换为IReadOnlyDictionary< TKey,TValue>,可能完全避免这个问题.即使问题不是不可避免的(例如,在某个地方,对其中一个接口进行了转换),实现两个扩展方法仍然会更好,每个接口一个.
我想在完成这个主题之前还需要一个程序问题.铸造字典< TKey,TValue>到IReadOnlyDictionary< TKey,TValue>只确保接收到铸造值的任何东西本身都不能改变底层集合.但是,这并不意味着对创建转换引用的字典实例的其他引用不会改变底层集合.这是IReadOnly *集合接口背后的抱怨之一 – 这些接口引用的集合可能不是真正的“只读”(或者,通常是暗示的,不可变的)集合,它们只是通过特定的引用来防止集合的变异(尽管有一个具体的ReadOnly *类的实际实例).这是(以及其他)创建集合类的System.Collections.Immutable命名空间的一个原因.此命名空间中的集合表示真正不可变的集合.这些集合的“突变”导致返回由突变状态组成的全新集合,使原始集合不受影响.