Can you use variables in your own initialization string (tryGetOrElse in the dictionary)?

Consider the following code:

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; }); } 

I am talking specifically about the initialization of a trader variable in closure, which uses itself in the same line in which it is created.

I have been using this template for working with dictionaries recently because I really don't like uninitialized variables :) and would like to know if this is guaranteed in the future.

+4
source share
3 answers

Besides the fact that you look very strange, there is nothing wrong with that - technically. First, a trader declaration will be declared, so there is a Trader object without an assigned value. Secondly, the TryGetValue part is evaluated and returns either true or false. If he returns, the now assigned trader returns. If it returns false, a new trader is created and added to the dictionary through the assignment operation. The result of the assignment operation is the value of the object to which it was assigned. This is a new trader. Third, the result of the ternary operator will be returned and assigned to trader .

It is unlikely that this will change in the future, because a change in the evaluation order of such a statement changes dramatically.

UPDATE:
Because it looks very strange, I would not use it. I would solve this problem by creating an extension method for IDictionary<TKey, TValue> called GetOrAdd .
It might look like this:

 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; } 

You would call it like this:

 var trader = traderSet.GetOrAdd(key, k => new Trader(s.gateway, s.broker)); 

This cleaner is a lot and it is even shorter than your weird approach.

BTW: You can use ConcurrentDictionary<TKey, TValue> . This class already has a GetOrAdd method and has the advantage of thread safety.

+5
source

Warranty is a strong word, but it is very, very, very unlikely that it will stop compiling in the future - language teams tend to maintain backward compatibility and, if there is no huge paradigm shift (i.e. from VB6 to the first VB.NET), this code should continue to work normally.

I really find this a nice trick, but it took me a while to see that TryGetValue was used in a triple operation (and other people had the same problem), so you can save one line of code here (moving the trader’s ad on one line), but this may require an additional service charge that you will pay later (or someone who inherits this code), so you might want to reconsider splitting the declaration ...

 Trader trader; trader = traderSet.TryGetValue(key, out trader) ? ... 
+2
source
 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); } 

I don’t see anything wrong with what you are doing, although I’m not sure if this is better than a simple alternative that does not require future programmers to develop code.

+1
source

All Articles