你可以在他们自己的初始化行中使用变量(字典中的tryGetOrElse)吗?

时间:2011-07-21 15:34:10

标签: c# linq dictionary

请考虑以下代码:

private Dictionary<RobotSettings, Trader> createTradersFor(IEnumerable<RobotSettings> settings)
{
    var traderSet = new Dictionary<Tuple<IGateway, IBroker>, Trader>();

    return settings.ToDictionary(s => s, s =>
    {
        var key = Tuple.Create(s.gateway, s.broker);

        Trader trader = traderSet.TryGetValue(key, out trader)
            ? trader
            : traderSet[key] = new Trader(s.gateway, s.broker);
        return trader;
    });
}

我正在谈论闭包中的trader变量的初始化,它在实例化的同一行中使用它自己。

我最近一直在使用这种处理字典的模式,因为我真的不喜欢未初始化的变量:)并且想知道这是否有保证将来编译。

3 个答案:

答案 0 :(得分:5)

除了看起来很奇怪之外,它没有任何问题 - 技术上 首先,将执行trader的声明,因此存在没有指定值的Trader对象。 其次,评估TryGetValue部分并返回true或false。如果返回true,则返回现在分配的trader。如果它返回false,则创建一个新的Trader并通过赋值操作将其添加到字典中。赋值操作的结果是分配给的对象的值。那是新的交易员。 第三,将返回三元运算符的结果并将其分配给trader

将来这种情况不太可能发生变化,因为改变这样一个声明的评估顺序是一个非常突破的变化。

<强>更新
因为它看起来很奇怪,我不会用它。我会通过为名为IDictionary<TKey, TValue>的{​​{1}}创建扩展方法来解决此问题 它可能看起来像这样:

GetOrAdd

你会这样称呼:

public static TValue GetOrAdd<TKey, TValue>(this IDictionary<TKey, TValue> dict,
                                            TKey key, Func<TKey, TValue> creator)
{
    TValue value;
    if(!dict.TryGetValue(key, out value))
    {
        value = creator(key);
        dict.Add(key, value);
    }
    return value;
}

这是很多清洁工,它甚至比你奇怪的方法更短。

BTW:您可以使用ConcurrentDictionary<TKey, TValue>代替。该类已经有一个方法var trader = traderSet.GetOrAdd(key, k => new Trader(s.gateway, s.broker)); ,并且具有线程安全的好处。

答案 1 :(得分:2)

保证是一个强有力的词,但它将非常,非常,非常不可能在将来停止编译 - 语言团队努力保持向后兼容性,除非有一个巨大的范式转换(即从VB6到第一个VB) .NET),此代码应继续正常构建。

我实际上认为这是一个很好的技巧,但我花了一些时间才看到TryGetValue用于三元操作(其他人有同样的问题),所以你可能在这里保存一行代码(移动交易员声明一行),但是稍后可能需要支付额外的维护费用(或者继承此代码的人),所以也许你应该重新考虑拆分声明......

Trader trader;
trader = traderSet.TryGetValue(key, out trader) ?
...

答案 2 :(得分:1)

Trader trader = traderSet.TryGetValue(key, out trader)
    ? trader
    : traderSet[key] = new Trader(s.gateway, s.broker);

VS

Trader trader;
if (!traderSet.TryGetValue(key, out trader)) {
    trader = traderSet[key] = new Trader(s.gateway, s.broker);
}

我也没有看到你正在做什么有什么问题,虽然我不确定它是否比直接的替代方案更好,不需要未来的程序员弄清楚代码的作用。