Reputation: 19
I have the following code at least 10 different times in my code. Seems kind of smelly to me.
public void DisplayTransitInfo(TransitInfo transitInfo)
{
if (InvokeRequired)
EndInvoke(BeginInvoke(new MethodInvoker(() => DisplayTransitInfo(transitInfo))));
else
{
var control = (from string key in _visiblePanes.Keys
where key == "transitInfo"
select _visiblePanes[key].Control).ToList();
TransitInfoControl cntl = (TransitInfoControl)control[0];
//TODO: Transit Info
}
}
public void ModifyParties(UltraTreeNode node)
{
if (InvokeRequired)
EndInvoke(BeginInvoke(new MethodInvoker(() => ModifyParties(node))));
else
{
var control = (from string key in _visiblePanes.Keys
where key == "parties"
select _visiblePanes[key].Control).ToList();
PartiesControl cntl = (PartiesControl)control[0];
cntl.ModifyParties(node);
}
}
I feel that it could be possible to use generics in this situation. I have also considered moving:
var control = (from string key in _visiblePanes.Keys
where key == "parties"
select _visiblePanes[key].Control).ToList();
to its own function that would return the instance of the control in the dictionary.
Is this code smelly or do I just need to get my nose worked on?
Thanks as always!
Upvotes: 0
Views: 128
Reputation: 133995
I may be missing something, but it seems to me you can get rid of the whole LINQ expression there there. That is, this code:
var control = (from string key in _visiblePanes.Keys
where key == "parties"
select _visiblePanes[key].Control).ToList();
PartiesControl cntl = (PartiesControl)control[0];
If I'm reading that right, you're enumerating a keyed collection to find all of the items that have the key "parties". But since you write _visiblePanes[key].Control
, it seems like there's just one of them. I'm going to assume that _visiblePanes
is a Dictionary<string, BaseControl>
, where BaseControl
is whatever class PartiesControl
and your other control types inherit from.
BaseControl cntl;
if (_visiblePanes.TryGetValue("parties", out cntl))
{
PartiesControl pcntl = cntl as PartiesControl;
// do whatever
}
Upvotes: 2
Reputation: 43046
If you are looking to simplify
var control = (from string key in _visiblePanes.Keys
where key == "transitInfo"
select _visiblePanes[key].Control).ToList();
TransitInfoControl cntl = (TransitInfoControl)control[0];
and
var control = (from string key in _visiblePanes.Keys
where key == "parties"
select _visiblePanes[key].Control).ToList();
PartiesControl cntl = (PartiesControl)control[0];
And if _visiblePanes is a dictionary, which implies it can have no duplicate keys, then you don't need generics, just use this instead:
var cntl = (TransitInfoControl)_visiblePanes["transitInfo"].Control;
and
var cntl = (PartiesControl)_visiblePanes["parties"].Control;
EDIT
(added casts above for equivalence with the original code)
This suggestion, compared with Jim Mischel's, is not only simpler to type and read, it is also closer to the original code, because it throws an exception if the key is not present in the dictionary. If the original code used Linq in an attempt to cover that possibility, it fails at PartiesControl cntl = (PartiesControl)control[0];
. Assuming that the absence of a key in the dictionary is non-exceptional, then, of course, Jim's TryGetValue
solution is better.
To return to the original question about generics, there is a possible advantage in extracting the get-and-cast logic into a generic method:
bool TryGetCast<T>(IDictionary<string, BaseControl> dict, string key, out T value) where T : BaseControl
{
BaseControl tryGet;
if (dict.TryGetValue(key, out tryGet)
{
value = (T)tryGet;
return true;
}
value = default(T);
return false;
}
can be called thus:
PartiesControl cntl;
if (TryGetCast(_visiblePanes, "parties", out cntl))
{
//do whatever;
}
However, the benefit is slight. Jim's solution plus a cast is not much more verbose:
BaseControl c;
if (_visiblePanes.TryGetValue("parties", out c))
{
var cntl = (PartiesControl)c;
// do whatever
}
Upvotes: 3
Reputation: 22379
If you have the same code 10 times in your application, it's definitely time to refactor!
Why do you write
(from string key in _visiblePanes.Keys
where key == "parties"
select _visiblePanes[key].Control)
when you can just use _visiblePanes["parties"]
(or use TryGetValue
if you're not sure whether the key exists)?
And why is control
a list? control
doesn't sound like the name of a collection.
Upvotes: 3