> I think what you're looking for is a Visitor.

Thanks for the links about reflection visitor. I used an approach very
much like that when implementing multiple xml format reader/writers for
a single object model.

But my main issue is if-else-if structures based on type, not the
example code in particular. Let's say the object model I'm processing is
not modifiable (third-party etc) so I cannot put a visitor pattern or
else into them.

Original problem where:

void Process(XmlNode node) {

   if (node is XmlElement) {
      XmlElement elem = (XmlElement)node;
      Console.WriteLine("Element: {0}", elem.Name);
      foreach (XmlAttribute attr in elem.Attributes)
        Process(attr);
      foreach (XmlNode child in elem.ChildNodes)
           Process(child);
   }
   else if (node is XmlAttribute) {
      XmlAttribute attr = (XmlAttribute)node;
      ...
   }
   else if (node is XmlText) {
      XmlText text = (XmlText)node;
      ...
   }
   else if (...) { ... }

}

FxCop will complain about this and yeas there will be multiple
classcasts of the same variable.

The alternative to make FxCop shut up (soon it will complain about
cyclomatic complexity though). If is also very ulgy, deeply nested, and
hard to change/maintain.

void Process(XmlNode node) {
   XmlElement elem = node as XmlElement;
   if (elem != null) {
      Console.WriteLine("Element: {0}", elem.Name);
      foreach (XmlAttribute attr in elem.Attributes)
        Process(attr);
      foreach (XmlNode child in elem.ChildNodes)
           Process(child);
   }
   else {
      XmlAttribute attr = node as XmlAttribute;
      if (attr != null)) {
      XmlAttribute attr = (XmlAttribute)node;
      ...
      }
      else {
         XmlText text = node as XmlText;
         if (text != null) {
            XmlText text = (XmlText)node;
            ...
         }
         else { ... }
      }
   }

}


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.

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
    }

}

// Kristofer
 

===================================
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