如何调用Dictionary .TryGetValue()其中K:Predicate ,V:enum

我有Dictionary<Predicate, SomeEnum>

 var dic = new Dictionary<Predicate, SomeEnum> { { (d) => d  d > 90, SomeEnum.Bar } }; 

我想像这样打电话给TryGetValue(K, out V)

 dic.TryGetValue(99) 

并收到

 SomeStruct.Bar 

TryGetValue()第一个参数是Predicate ,而不仅仅是T 我怎么能做我想做的事?

我发现只有一个肮脏的解决方法:

 var kpv = dic.FirstOrDefault(p => p.Key(99)); if (kpv.Key != null) var result = kpv.Value; 

还有其他方法吗?

或者如何正确实现我的想法? – 声明一个键不是一个常量,而是一个段。

这里有一些问题:

Predicate不适合用作TKey 。 字典的关键是识别一个值,而不是计算一个值。

使用lambdas也没有任何意义。 因为它们是匿名的,所以你不会得到任何等价,也不会使用字典。

有关说明,请参阅此代码示例:

 Predicate fn_1 = d => d == 34.0d; Predicate fn_2 = d => d == 34.0d; // Note: There are not equal if (fn_1 == fn_2) Console.WriteLine("These are Equal?"); 

如果有的话,您可以使用委托列表并执行每个委托以查找匹配的委托,但此时您必须预期多个结果。 如果您只想获得单个结果,则必须考虑谓词在列表中的存储顺序

不要滥用KeyValuePair作为没有Tuple的黑客攻击。 创建一个既包含Predicate又包含SomeStruct的类相当容易。 看:

 public class MySegment { public Predicate Predicate {get;set;} public SomeStruct Result {get;set;} } 

要查看一系列谓词,找到匹配的谓词,如下所示:

 ... List list = new List(); ... list.Add(new MySegment { Predicate = d => d < 10, Result = SomeStruct.Foo }); list.Add(new MySegment { Predicate = d => d > 90, Result = SomeStruct.Bar }); ... public IEnumerable GetResults(double input) { foreach (var item in list) if (item.Predicate(input)) yield return item.Result; } 

如果您的谓词列表不是太长,您只需将它们添加到List, V>> ,然后执行LINQ查询:

 var lt10 = new KeyValuePair, SomeStruct>(d => d < 10, SomeStruct.Foo); var gt90 = new KeyValuePair, SomeStruct>(d => d > 90, SomeStruct.Bar); var predicates = new List, SomeStruct>>() { lt10, gt90 }; var result = predicates.FirstOrDefault(p => p.Key(99)); 

你最好使用SomeStruct? 而且,从那时起, FirstOrDefault将提供一个明确的结果,如果它不匹配任何一个,而不是SomeStruct

如果列表很长,则需要考虑某种允许查询范围的数据结构,如间隔树 。

这不能使用Dictionary来完成,因为它依赖于哈希值来快速确定在哪里查找特定键。

正如您所发现的,您可以直接调用谓词,但这需要调用O(n)函数,这不比使用List,甚至是大的if / then / else语句更好。

如果您的潜在谓词集合太长而无法选择,那么您需要创建自己的数据结构以满足您的目的。 如果您只打算根据整数范围定义值,这应该不难,但如果您的谓词变得更复杂,它可能会失控。

另一方面,F#语言使用Match Expressions内置支持这种定义。 我不知道如何编译分支,但我认为它相当聪明。

编辑

以下是在F#中使用匹配表达式的示例:

 // Define the "choose" function let choose value = match value with | v when v < 10 -> 1 | v when v > 90 -> 2 | _ -> 0 // Test the "choose" function let choice1 = choose 5 let choice2 = choose 15 let choice3 = choose 95 

上面的代码产生以下值:

 choice1 = 1 choice2 = 0 choice3 = 2 

我之前从未真正使用过F#,所以你必须四处寻找如何在C#程序中使用F#中的函数。

您必须遍历您的条件并针对输入运行每个谓词以查看它是否匹配。 我认为没有理由在这里使用词典。