请考虑以下代码:
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变量的初始化,它在实例化的同一行中使用它自己。
我最近一直在使用这种处理字典的模式,因为我真的不喜欢未初始化的变量:)并且想知道这是否有保证将来编译。
答案 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);
}
我也没有看到你正在做什么有什么问题,虽然我不确定它是否比直接的替代方案更好,不需要未来的程序员弄清楚代码的作用。