public static void Main()
var resultVisitor = new QueryResultVisitor(new ControllerContext());
var profile = new UserProfileResult("userId");
var profileAction = profile.Visit(resultVisitor);
Console.WriteLine(profileAction);
var error = new ValidationErrorResult("Error");
var errorAction = error.Visit(resultVisitor);
Console.WriteLine(errorAction);
var search = new SearchQueryResult("keyword");
var searchAction = search.Visit(resultVisitor);
Console.WriteLine(searchAction);
T Visit<T>(IQueryResultVisitor<T> visitor);
public interface IQueryResultVisitor<T>
T Visit(ValidationErrorResult result);
T Visit(UserProfileResult result);
T Visit(SearchQueryResult result);
public abstract class QueryResult : IQueryResult
public T Visit<T>(IQueryResultVisitor<T> visitor)
return visitor.Visit(this as dynamic);
public class UserProfileResult : QueryResult
public string UserId { get; set; }
public UserProfileResult(string userId)
public class ValidationErrorResult : QueryResult
public string Message { get; set; }
public ValidationErrorResult(string message)
public class SearchQueryResult : QueryResult
public string Keyword { get; set; }
public SearchQueryResult(string keyword)
public class QueryResultVisitor: IQueryResultVisitor<ActionResult>
private IControllerContext Context { get; set; }
public QueryResultVisitor(IControllerContext context)
public ActionResult Visit(ValidationErrorResult result)
return Context.RenderError(result.Message);
public ActionResult Visit(UserProfileResult result)
return Context.Redirect("Profile", new { user = result.UserId });
public ActionResult Visit(SearchQueryResult result)
return Context.Redirect("Search", new { q = result.Keyword });
public class ActionResult
public string Message { get; set; }
public override string ToString()
public interface IControllerContext
ActionResult RenderError(string errorMessage);
ActionResult Redirect(string page, object param);
public class ControllerContext : IControllerContext
public ActionResult RenderError(string errorMessage)
return new ActionResult {Message = errorMessage};
public ActionResult Redirect(string page, object routeValues)
return new ActionResult {Message = page};