I have a hierarchical data tree containing objects of a class called DataNode
.
Each DataNode
contains a collection of Attribute
objects. Each Attribute
is essentially a key/value pair, with some helper methods attached. For example, there is a helper method called EqualsCodeIndex(x)
that matches a small collection x
of int
values to this
attribute
and returns true
or false
. All keys and values are strings, because the whole thing is based on a key/value store contained in a text file.
To simplify access to a particular DataNode
, there is a dictionary in the DataTree
class that maps all of the nodes in the tree to a unique code:
Dictionary<string, Dat开发者_Python百科aNode> Codes;
The resulting Linq statement to get to a specific Attribute
value looks like this:
string AttributeValue = dataTree
.Codes[@"R-1\CHE"]
.Attributes
.Single(x => x.EqualsCodeIndex(parentAttribute.CodeIndex))
.Value.Trim();
This is not too bad if I only have to retrieve one or two attributes by code and code index, but it's not so good if I have to retrieve ten or more.
To attempt to simplify the statement, and allow for the possibility of EqualsCodeIndex
returning false
for all attributes in the collection, I added an extension method:
public static string AttributeValueMatching
(this KeyValuePair<string, DataNode> pair, List<int> codeIndex)
{
var attribute = pair.Value.Attributes
.Single(x => x.EqualsCodeIndex(codeIndex))
return attribute == null ? string.Empty : value;
}
This simplifies the original linq statement down to:
string attributeValue
= dataTree.Codes[@"R-1\CHE"].AttributeValueMatching(codeIndex);
...which is better, but I have a feeling I'm missing something.
Are there problems with this approach? Is there a better, cleaner approach I haven't thought of, maybe making better use of indexers, or perhaps a fluent interface?
I think that making it into one method with two parameters would look slightly better:
Codes.AttributeValueMatching(@"R-1\CHE", codeIndex)
Or you could create a wrapper with an indexer:
CodesWrapper[@"R-1\CHE", codeIndex]
I don't have a direct answer to your whole question, but to the "problems with this approach" section I have a suggestion.
Be careful chaining statements after a SingleOrDefault()
as it could potentially return null
. If you are absolutely sure it will always have a single value, maybe just call Single()
and deal with that missed expectation should it ever happen instead of a more generic NullReferenceException
.
EDIT While writing the above post you made the same changes. Carry on...
Have you considered building an Extension Method of DataTree?
like
public static class DataTreeExtensions
{
public static string FetchByAttribute(this DataTree d, string Attribute)
{
string AttributeValue = d
.Codes[Attribute]
.Attributes
.Single(x => x.EqualsCodeIndex(parentAttribute.CodeIndex))
.Value.Trim();
return AttributeValue
}
}
This will allow you to reuse "FetchByAttribute" at will as:
string myValue = myTree.FetchByAttribute(@"R-1\CHE");
Edited: changed from DataNode to DataTree...
精彩评论