Jul
 
  13
 
 
  
   Written by:
   kchristo
  
  
  Friday, July 13, 2012 
   
 
 
 
 
 
 
  
 
 One of my favorite design patterns since the age of c++ is the 
Visitor Pattern. I will not explain here what the 
visitor pattern is. But, if you know how to use the design pattern this is a post worth reading.     
One may ask what the visitor pattern has to do with LightSwitch. Well, it doesn’t! I mean not exclusively. But the code below provides a full visitor pattern implementation background that can also be used in LS. Also, a part of the implementation is ideal for LS, since one of the challenges I had to face, when trying to widely use the visitor pattern, was make it work for “sealed” classes, classes that were not written by me and could not easily fit to my –reflection based- visitor pattern implementation. To solve this the best thing I could think of was “wrapping”. And working with LS, most of the classes (apart from the ones that belong to the domain/datasource) are actually “sealed” in the way described above.(I have to note here that this reflection-based implementation is a revision of an implementation I found (if I recall correct) in CodeProject).     
First the two basic interfaces that have to be defined:     
The 
IVisitor interface that has to be implemented by the “worker” (or helper to follow the VB-oriented naming of the LS Team 

) class.     
   public interface IVisitor
{
  void VisitDefault(IVisitorTarget source);
}
 
  
  
  
Then the IVisitorTarget interface (implied above) that has to be implemented by the class to be “consumed/visited” by the Visitor. 
  
  public interface IVisitorTarget
{
  void Accept(IVisitor visitor);
}
 
  
  
  
Ok, I know, nothing much up to now. But as I say “The longest journey starts with the first step”…(yes I am an old Chinese philosopher) 
  
  
To have your visitor pattern in place you need an extension method to do the trick: 
  
  public static bool ConcreteVisit(this IVisitorTarget target, IVisitor visitor) {
  Type[] types = new Type[] { target.GetType() };
  MethodInfo mi = visitor.GetType().GetMethod("Visit", types);
  if (mi == null)
    return false;
  mi.Invoke(visitor, new object[] { target });
  return true;
}
 
  
Now that these pieces are in place let’s say we have a class called DisplayNameBuilder that implements the IVisitor interface. Also, let’s say we have a Customer entity in our datasource and we want it to implement the IVisitorTarget interface. All we have to do is open Customer entity in the designer, click Write Code and change the class declaration to: 
  
  public partial class Model : IVisitorTarget
 
  
  
  
make sure you are using the namespace of the class where the above extension method is implemented and implement the IVisitorTarget interface like this: 
  
  #region IVisitorTarget Members
public void Accept(IVisitor visitor) {
  if (!this.ConcreteVisit(visitor))
    visitor.VisitDefault(this);
}
#endregion
 
  
  
  
Also this is a sample implementation of the DisplayNameBuilder class: 
  
  public class DisplayNameBuilder : IVisitor
{
  public string Name{
    get;
    private set;
  }
  public void VisitDefault(IVisitorTarget visitorTarget){
    Name = visitorTarget.ToString();
  }
  public void Visit(Customer visitorTarget){
    Name = string.Format("{0}{1}{2}", visitorTarget.FirstName, string.IsNullOrWhiteSpace(visitorTarget.FirstName) ? "", " ", visitorTarget.LastName);
  }
}
 
  
  
  
In the above code please note these: 
  
  
  
    
    - The code was written in Live Writer as it’s demo code, so maybe it does not compile as is.  
 
- The customer is implied to have a nullable FirstName property and a not nullable LastName (which I believe it’s a fair assumption and I agree with me). 
      
 
- The implementation, as obvious, is domain aware as it knows what Customer is. This implies that the ideal place for this class to live is in the Common project. 
 
Now lets say you create a calculated string field in Customer entity called hmmmmm… 
DisplayName (surprised? It’s a gift I have regarding giving original names

). This would be the code that would implement the calculation of 
DisplayName property: 
partial void DisplayName_Compute(ref string result) {
  DisplayNameBuilder builder = new DisplayNameBuilder();
  this.Accept(builder);
  result = builder.Name;
}
I HAVE to stress one more time that the code is for demonstration purposes only. It’s not just you, it IS too much fuss for nothing. 
Ok, now it should be easier to understand the problem of using the visitor pattern with pre-defined classes. You cannot add the 
IVisitorTarget behavior to most of the classes, automatically generated by LS. 
So this is the solution to the problem. 
public class IVisitorWrapper<TObjectType> : IVisitorTarget
{
  public TObjectType Content {
    get;
    set;
  }
  #region IVisitorTarget Members
  public void Accept(IVisitor visitor) {
    if (!this.ConcreteVisit(this, visitor))
      if (!this.VisitWrapper(this, visitor))
        visitor.VisitDefault(this);
  }
  #endregion
}
This is a wrapper class (one could say it is an 
IVisitorTarget decorator). If you are still with me and you keep on reading the code you have already noticed that 
VisitWrapper extension method is not yet defined, so this is it: 
public static bool VisitWrapper<TObjectType>(this IVisitorWrapper<TObjectType> wrapper, IVisitor visitor) {
  Type[] types = new Type[] { typeof(TObjectType) };
  MethodInfo mi = visitor.GetType().GetMethod("Visit", types);
  if (mi == null)
    return false;
  mi.Invoke(visitor, new object[] { wrapper.Content });
  return true;
}
  
  
  
Now you can wrap any type of object and use the DisplayNameBuilder to build it’s display name. Also (as –I hope- you guessed) you have to implement the respective Visit method in DisplayNameBuilder in order not go get the type name back as Name. 
This is a small sample of how the wrapper can be used:
  
WhateverObject objectToWrap = new WhateverObject();
DisplayNameBuilder builder = new DisplayNameBuilder();
new IVisitorWrapper<WhateverObject> { Content = objectToWrap }.Accept(builder);
string displayName = builder.Name;
  
  
  Well, as Porky says: That’s all Folks 

. I hope that except for exhausting it was also interesting.
 
  
 
 
 
 
 
 
 
 
		
  
   
   10 comment(s) so far...
  
  
  
  
			
				| 
					
     
      
      By rachelle on 
       
      Tuesday, June 24, 2014
       
       
       
       
       
       
       
       
       Thank you for posting some kind of information. It was really helpful since I am doing some research now. .
 Dianne
 www.imarksweb.org
 | 
				| 
					
     
      
      By dhanne on 
       
      Tuesday, July 22, 2014
       
       
       
       
       
       
       
       
       i enjoyed reading your blog post. thanks for sharing this informative one. till next time.
 www.triciajoy.com
 | 
				| 
					
     
      
      By ufgop.org on 
       
      Wednesday, November 26, 2014
       
       
       
       
       
       
       
       
       Love it! Very interesting topics, I hope the incoming comments and suggestion are equally positive. Thank you for sharing this information that is actually helpful.
 
 ufgop.org
 ufgop.org
 | 
				| 
					
     
      
      By gofastek.com on 
       
      Wednesday, December 17, 2014
       
       
       
       
       
       
       
       
       Looking for a good site that is more interesting and knowledgeable? Here are some information that may useful for future reference. Visit our page @ www.gofastek.com..  
 cheun
 
 | 
				| 
					
     
      
      By michele on 
       
      Friday, September 11, 2015
       
       
       
       
       
       
       
       
       understand the problem of using the visitor pattern with pre-defined classes. visit my site too, check here chevysilverado2015.com
       | 
				| 
					
     
      
      By nailuns on 
       
      Monday, September 14, 2015
       
       
       
       
       
       
       
       
       Nice Info, Thank you for sharing this information that is actually helpfuly. 
 Visit  2016bestcarstrend.com
 | 
				| 
					
     
      
      By azkiya on 
       
      Monday, September 14, 2015
       
       
       
       
       
       
       
       
       Keep posting the articles,useful to every one. thank you
 Don't forget visit bestluxurycars2016.com
 | 
				| 
					
     
      
      By aboa on 
       
      Monday, September 14, 2015
       
       
       
       
       
       
       
       
       Interesting topic. I would like to add a little bit different topics
 Please visit 2016carsreleaseprice.com
 
 2016carsreleaseprice.com
 
 Thanks You
 | 
				| 
					
     
      
      By leewoo880 on 
       
      Thursday, September 29, 2016
       
       
       
       
       
       
       
       
       I really enjoyed reading your article. I found this as an informative and interesting post, so i think it is very useful and knowledgeable. I would like to thank you for the effort you have made in writing this article.
 
 
 edupdf.org
 
 | 
				| 
					
     
      
      By Anthony on 
       
      Thursday, January 6, 2022
       
       
       
       
       
       
       
       
       Nike Sneakers For MenJordan Shoes
 Nike Mags
 Nike Shoes
 Pandora Earrings
 Air Force 1
 Christian Louboutin Shoes
 Pandora Necklace For Women
 Nike Shoes 2019
 Nike Outlet Store
 Yeezy 500 Black
 Jordan 11 Gamma Blue
 Nike Running Shoes For Men
 Pandora Necklace
 Louboutin shoes
 Pandora Jewelry Outlet
 Pandora Earrings
 Nike Outlet Store
 Louboutin Shoes
 Pandora
 Louboutin Shoes
 Nike Free Run
 Nike Air Zoom Pegasus 36
 Christian Louboutin Shoes
 Pandora Canada
 Ferragamo Shoes
 Jordan Retro
 Nike Outlet
 Adidas Stan Smith
 Nike Outlet Online
 Lebron 16
 Ferragamo
 Christian Louboutin
 Nike Outlet Online
 Nike Air Force Ones
 NMD R1
 Nike Huarache
 Nike Shoes
 Air Jordan Sneakers
 Ultra Boost Adidas
 Nike Shoes
 Pandora Bracelets For Women
 Christian Louboutin Outlet
 Nike Factory Store Online
 Nike Shoes For Kids
 Nike Running Shoes
 Yeezy
 Nike Outlet
 Air Jordans
 Pandora Charms
 Air Max
 Pandora Official Website
 Lebron James Sneakers
 Nike Sneakers Sale
 Red Bottom Shoes
 Ultra Boost
 Pandora Canada
 Moncler UK
 Nike Outlet Store Online
 Pandora Rings
 Nike Lebron 16
 Air Force 1 Mid
 Yeezy Sneakers
 Nike Epic React
 Basketball Shoes
 Air Max 2019
 Nike Outlet Store
 Nike Running Shoes For Men
 Yeezys Boost 350 V2
 Michael Jordan Shoes
 Nike Shoes
 Kevin Durant Shoes
 Nike Zoom Pegasus
 NMD
 Christian Louboutin Shoes Outlet
 Air Max 95
 Pandora Canada
 Lebron 17 Low
 Jordan Shoes For Kids
 Kyrie Basketball Shoes
 Nike Shoes
 Red Bottom Shoes
 Christian Louboutin Shoes
 Nike Air Max 270
 Air Max 98
 Nike Cortez Women
 Christian Louboutin Outlet
 Nike Outlet Store
 Air Max 98
 Nike Clearance Outlet
 Pandora
 Pandora Charms
 Lebron James Shoes
 Pandora Charms
 Adidas Sneakers For Men
 Nike Shoes
 Cheap Nike
 Yeezy Boost 750
 Red Bottom Heels
 Nike Shoes
 Nike M2k Tekno
 Nike Sneakers
 Vans
 Nike Presto
 Fjallraven Backpack
 Nike Shoes 2019
 Nike
 Nike Black Friday Sale
 Jordan Retro
 Ferragamo
 Louboutin Outlet
 Kyrie Irving Basketball Shoes
 Valentino
 Nike Air Max 720
 Nike Air Max 720
 Cheap Yeezys
 Mens Nike Shoes
 Nike Factory Outlet
 Adidas Yeezys
 Sneakers Website
 Nike Metcon
 Basketball Shoes Nike
 Christian Louboutin Shoes
 Yeezy
 Nike Outlet Store
 Jordan 11
 Yeezy Shoes
 Fjallraven Backpack
 Nike Air Max 90
 Nike Outlet
 Nike Clearance Store
 Nike Store Online
 Golden Goose
 Adidas Yeezys
 Louboutin Outlet
 Pandora Bracelets
 Asics Shoes
 Nike Air Force
 Jordan 13 Retro
 Nike Outlet
 Nike Outlet Store Online Shopping
 Nike Clearance
 |