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

Reply via email to