在尝试使用ForEach调用键之前,检查键是否存在于Action's字典中

本文关键字:Action 存在 字典 是否 ForEach 调用 检查 | 更新日期: 2023-09-27 18:06:03

我有一个字典,其中键是一个字符串,值是一个动作。设置字符串键到函数的映射。然后我有一个列表,我调用。foreach(),并在其中使用列表中的值作为键,然后调用与之相关的函数。如果密钥不存在,问题就会出现。我如何在。foreach函数中检查这一点?我想使用三元运算符,但它似乎不起作用。

private Dictionary<string, Func<IniConfig, object>> typeMapping = new Dictionary<string, Func<IniConfig, object>>();
typeMapping["MB"] = ProcessMB;
public object ProcessMB(IniConfig file)
{
    return null;
}
object iif(bool expression, object truePart, object falsePart)
    { return expression ? truePart : falsePart; }
FilesToProcess.ForEach(x => iif(typeMapping.ContainsKey(x.ExtractType), typeMapping[x.ExtractType](x), Error(x)));

这突出显示了iif()调用中带有error的第二个形参:参数2:不能从'void'转换为'object', error (x)部分也是如此。

似乎三元操作符返回一个对象?因此,如果我将Action更改为Func并将返回类型为对象并使我的函数返回它编译的对象,但是当我使用无效键运行测试时,它不会进入我的Error()函数,它会抛出"给定键不存在于字典中"异常。我希望它执行三元操作,并看到typeMapping没有键,因此无法执行Error()函数。我错过了什么?

在尝试使用ForEach调用键之前,检查键是否存在于Action's字典中

您的iif()方法在这里是反直觉的,并且看起来像是过度使用LINQ。下面是我要做的:

foreach (var file in filesToProcess)
{
    Func<IniConfig, object> action;
    if (typeMapping.TryGetValue(file.ExtractType, out action))
    {
        action(file);
    }
    else
    {
        Error(file);
    }
}

让你的代码更容易阅读:)

编辑:

我已经找到了一种通用的方法来做你想做的事。首先,您需要为IDictionary<TKey,TVal>创建一个扩展方法,如果键不存在,它只返回默认值:
public static TVal GetValueOrDefault<TKey, TVal>(this IDictionary<TKey, TVal> self, TKey key)
{
    TVal ret;
    self.TryGetValue(key, out ret);
    return ret;
}

那么你可以使用空合并(??)运算符:

FilesToProcess.ForEach((typeMapping.GetValueOrDefault(x.ExtractType) ?? Error)(x));

让您的生活变得简单,只需创建一个小的辅助函数来做您想做的事情:

private void InvokeProcessor(IniConfig iniConfig)
{
    Func<IniConfig, object> processor;
    if (typeMapping.TryGetValue(x.ExtractType, out processor)
        processor(iniConfig);
    else
        Error(iniConfig);
}

然后像这样使用:

FilesToProcess.ForEach(InvokeProcessor);

易于阅读和理解。而且更快,因为每个文件只需要搜索一次字典。

编辑

好吧,如果你真的想使用奇怪的iif(),这里是如何修复它:

object iif(bool expression, Func<object> truePart, Func<object> falsePart)
    { return expression ? truePart() : falsePart(); }

…以及如何使用它:

FilesToProcess.ForEach(x => iif(
    typeMapping.ContainsKey(x.ExtractType), 
    () => typeMapping[x.ExtractType](x), 
    () => Error(x)));

基本上iif()的2和3rd参数的求值是延迟的,直到其中一个是实际需要的。在以前的版本中,所有参数都在执行iff()之前求值,导致每次处理IniConfig对象时调用字典索引器调用Error()

一个警告:如果你在生产中使用这个,那么harakiri可能是你唯一的出路,它将在几年后战胜你。