At 05:13 AM 7/18/2006, Krebs Kristofer wrote
>> I think what you're looking for is a Visitor.
>[snip]
>Let's say the object model I'm processing is not modifiable (third-party etc)
>so I cannot put a visitor pattern or else [sic] into them.
>[snip]
>So, I thought a little about using generics and came up with the following:
>
>void Process(XmlNode node) {
> XmlElement elem;
> XmlAttrbute attr;
> XmlText text;
>
> if (IsType(node, out elem)) {
> Console.WriteLine("Element: {0}", elem.Name);
> foreach (XmlAttribute eattr in elem.Attributes)
> Process(eattr);
> foreach (XmlNode child in elem.ChildNodes)
> Process(child);
> }
> else if (IsType(node, out attr)) {
> // Print attribute
> }
> else if (IsType(node, out text)) {
> // Print text node
> }
> else if (...) { ... }
>
>}
>
>private bool IsType<T>(object source, out T target) where T : XmlNode {
> target = source as T;
> return (target != null);
>}
>
>What do you think? I have not yet checked the IL, but FxCop does not complain
>anymore and the structure is still, if not more, clear than in the original
>case.
That looks like a workable solution, as it removes the deeply-nested issue that
exists in the original. But it doesn't really address the "one really big
method" issue that would arise if there are dozens (or hundreds) of different
classes/classes involved.
If you are ok with reflection, you could make a class (see note below) with
methods for the different types:
public void DoElement(XMLElement elem) {...}
public void DoText(XMLText text) {...}
public void DoAttribute(XMLAttribute attr) {...}
and use reflection to build a list of Type / MethodInfo pairs. (You'd go
through all the class's MethodInfo values, and get the datatype of the first
parameter.) Then you could iterate through that structure and use
thisMethodInfo.Invoke to call the first method where the node you're processing
is an instance of the parameter type associated with that method.
(note) You could have many different classes for different activities; in some
situations, you wouldn't need details for some classes/types that you might
care about later. The class could be chosen at runtime. (end note)
If the class hierarchy being checked were to be multi-level, you'd want to call
the method defined for the most-deeply-derived-in-the-hierarchy type that the
class actually contains, and call the method for the parent type if there isn't
a method for the child type. That could end up with a reliance on the sequence
of the MethodInfo values returned by reflection matching the sequence of the
method defns in the source code AND on future developers putting the methods
for new types in the right sequence within the class. (But you should be able
to sort the data structure -- left as an exercise for the reader.)
>What you really would want is some kind of language feature like you have for
>exceptions:
>
>void Process(XmlNode node) {
>
> trycast (node) {
> case (XmlElement elem): {
> // Print element
> }
> case (XmlAttribute attr): {
> // Print attribute
> }
> case (...): {
> }
> default:
> // Unhandled type
> }
>
>}
I wouldn't want a language feature to be added when your IsType<T> solution
does the same thing.
>// Kristofer
Thanks for a most interesting topic, BTW!
J. Merrill / Analytical Software Corp
===================================
This list is hosted by DevelopMentorĀ® http://www.develop.com
View archives and manage your subscription(s) at http://discuss.develop.com