【问题标题】:Operations over dictionary-key without System.Collections.Generic.KeyNotFoundException没有 System.Collections.Generic.KeyNotFoundException 的字典键操作
【发布时间】:2021-12-14 09:31:58
【问题描述】:

我有一个简单的字典调用结果:

Dictionary<String,String> results=new();
results["a"]="a";
results["b"]="b";
results["c"]="c";

为了简化示例,我的字典仅包含 3 个字母键 a、b、c。 但有时它不会包含这些值之一,甚至不包含(它总是会被初始化)。 假设这种情况:

Dictionary<String,String> results=new();
if(anyconditionA) results["a"]="a";
if(anyconditionB)results["b"]="b";
if(anyconditionC)results["c"]="c";

所以每次我想使用这本字典进行操作时,我都必须检查键值: 变种测试=结果[“一”]; -> 如果 anycontitionA 不为真,则抛出 System.Collections.Generic.KeyNotFoundException。 所以要解决这个问题:

if(results.ContainsKey("a"){
  someOperation(results["a"]);
}

所以如果我有很多值代码如下所示:

if(results.ContainsKey("a"){someOperation(results["a"]);}
if(results.ContainsKey("b"){... stuff}
if(results.ContainsKey("c"){... stuff}
if(results.ContainsKey("..."){... stuff}
if(results.ContainsKey("d"){someOperation(results["d"]);}

¿在一个语句中是否有适当的方法来执行此操作,我的意思是检查并在存在时执行操作,或者我必须在每次该值存在时进行测试? (就像在列表中使用 null 运算符一样 结果[a]?.someOperation() ) 谢谢!

【问题讨论】:

标签: c# .net linq dictionary keynotfoundexception


【解决方案1】:

如果你发现自己经常这样做并且想要简化调用代码,你可以编写一个扩展方法:

public static class DictionaryExt
{
    public static bool DoIfExists<TKey, TValue>(this Dictionary<TKey, TValue> self, TKey key, Action<TValue> action)
    {
        if (!self.TryGetValue(key, out var value))
            return false;

        action(value);
        return true;
    }
}

那么你可以这样写代码:

results.DoIfExists("a", someOperation);

results.DoIfExists("b", value => Console.WriteLine("Doing stuff with " + value));

results.DoIfExists("c", value =>
{
    Console.WriteLine("Doing stuff with " + value);
    Console.WriteLine("This uses multiple lines.");
});

我真的不确定这是否值得(我不喜欢过度使用扩展方法),但这是见仁见智的问题!

在我看来,上面的第三个例子混淆了代码,最好写成:

if (results.TryGetValue("c", out var value))
{
    Console.WriteLine("Doing stuff with " + value);
    Console.WriteLine("This uses multiple lines.");
}

但第一个示例 results.DoIfExists("a", someOperation); 可以说比:

if (results.TryGetValue("a", out var value))
    someOperation(value);

这是一个微小的改进,我个人不会打扰。这取决于你!

【讨论】:

  • 哈,这和我刚刚写的代码几乎一模一样,然后我(我猜也是)得出结论,dictionary.InvokeIfExists(key, someMethod); 并没有真正节省超过if(dictionary.TryGetValue(key, out var x)) someMethod(x) 的任何东西
  • @Matthew Watson(这是一个边际改进......)可能在我的例子中,但我问这个是因为我使用具有 100 个变量的代码并且总是相同的情况 check-do check-do 和这很烦人哈哈
  • 总是值得发布实际示例而不是人为的示例,然后我们可以看看是否有一些替代的保存/策略可供选择
  • @hesolar DoIfExists() 是上面public static class DictionaryExt 中的扩展方法。您需要确保已在与使用它的代码相同的命名空间中定义了DictionaryExt,或者您在文件顶部指定了using DictionaryExtNamespace(其中DictionaryExtNamespace 是您放置DictionaryExt 的命名空间)。详见this Microsoft documentation,尤其是示例代码using CustomExtensions;
  • @hesolar - 我知道;你必须写它。实际上 Matthew 已经写好了,您只需复制该代码并将其粘贴到您的项目中的某个地方。通常我们在一个用于扩展方法的专用类中这样做。长话短说:在您的项目中创建一个新的类文件并将其命名为 DictionaryExt; VS 将添加一些带有namespace Whatever{ class DictionaryExt { } } 之类的命名空间的大部分为空的类文件,删除class DictionaryExt { } 并粘贴马修回答中第一个代码块的内容。然后一切都会正常
【解决方案2】:

您从 Matthew Watson 那里得到了“如果键不在字典中,则可能不要调用获取值的操作”,但在问题的最后,您询问了一个稍微不同的问题

¿在一个语句中是否有适当的方法来执行此操作,我的意思是检查并在存在时执行操作,或者我必须在每次该值存在时进行测试? (就像列表中的 null 运算符一样 results[a]?.someOperation() )谢谢!

如果操作是对字典中值的方法,那么可以肯定,您可以使用?. 来防止对不存在的值产生空引用:

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

        dictionary.GetValueOrDefault(1)?.AppendLine("hello");

GetValueOrDefault 实现 as an extension method 并且是 .net core 2.2+ 的东西。有一些 nuget 包使其可用于旧版本,或者您可以自己编写它作为扩展,可能从 the netcore source 改编它并将其放入您的应用程序中:

    public static TValue? GetValueOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key)
    {
        return dictionary.GetValueOrDefault(key, default!);
    }

    public static TValue GetValueOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue)
    {
        if (dictionary == null)
        {
            throw new ArgumentNullException(nameof(dictionary));
        }

        TValue? value;
        return dictionary.TryGetValue(key, out value) ? value : defaultValue;
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多