In Scala, you can use pattern matching to produce a result depending on the type of the input. For instance:
val title = content match {
case blogPost: BlogPost => blogPost.blog.title + ": " + blogPost.title
case blog: Blog => blog.title
}
In C#, I'd ideally like to be able to write:
var title = Visit(content,
(BlogPost blogPost) => blogPost.Blog.Title + ": " + blogPost.Title,
(Blog blog) => blog.Title
);
Is this possible? When I've tried writing it as a single method, I don't know how to specify the generics. The following implementation seems right, apart from getting the type checker to allow functions that accept subtypes of T:
public TResult Visit<T, TResult>(T value, params Func<T, TResult>[] visitors)
{
foreach (var visitor in visitors)
{
if (visitor.Method.GetGenericArguments()[0].IsAssignableFrom(value.GetType()))
{
return visitor(value);
}
}
throw new ApplicationException("No match");
}
The closest I've gotten is to add the functions to an object individually, and then call visit on a value:
public class Visitor<T, TResult>
{
private class Result
{
public bool HasResult;
public TResult ResultValue;
}
private readonly IList<Func<T, Result>> m_Visitors = new List<Func<T, Result>>();
public TResult Visit(T value)
{
foreach (var visitor in m_Visitors)
{
var result = visitor(value);
if (result.HasResult)
{
return result.ResultValue;
}
}
throw new ApplicationException("No match");
}
public Visitor<T, TResult> Add<TIn>(Func<TIn, TResult> visitor) where TIn : T
{
m_Visitors.Add(value =>
{
if (value is TIn)
{
return new Result { HasResult = true, ResultValue = visitor((TIn)value) };
}
return new Result { HasResult = false };
});
return this;
}
}
This can be used like so:
var title = new Visitor<IContent, string>()
.Add((BlogPost blogPost) => blogPost.Blog.Title + ": " + blogPost.Title)
.Add((Blog blog) => blog.Title)
.Visit(content);
Any idea how to do this with a single method call?
Pattern matching in C− We have to find if a string is present in another string, as an example, the string "algorithm” is present within the string "naive algorithm". If it is found, then its location (i.e. position it is present at) is displayed.
A regular expression is a sequence of characters used to match a pattern to a string. The expression can be used for searching text and validating input. Remember, a regular expression is not the property of a particular language. POSIX is a well-known library used for regular expressions in C.
When pattern matching, we assert that a certain piece of data is equal to a certain pattern. For example, in the function: head (element:list) = element. We assert that the first element of head 's argument is called element, and the function returns this.
Pattern matching is a technique where you test an expression to determine if it has certain characteristics. C# pattern matching provides more concise syntax for testing expressions and taking action when an expression matches.
Pattern matching is one of those lovely features mostly found in functional programming languages like F#. There is a great project going on in codeplex named Functional C#. Consider the following F# code:
let operator x = match x with
| ExpressionType.Add -> "+"
let rec toString exp = match exp with
| LambdaExpression(args, body) -> toString(body)
| ParameterExpression(name) -> name
| BinaryExpression(op,l,r) -> sprintf "%s %s %s" (toString l) (operator op) (toString r)
Using the Functional C# library, the C# equivalent would be:
var Op = new Dictionary<ExpressionType, string> { { ExpressionType.Add, "+" } };
Expression<Func<int,int,int>> add = (x,y) => x + y;
Func<Expression, string> toString = null;
toString = exp =>
exp.Match()
.With<LambdaExpression>(l => toString(l.Body))
.With<ParameterExpression>(p => p.Name)
.With<BinaryExpression>(b => String.Format("{0} {1} {2}", toString(b.Left), Op[b.NodeType], toString(b.Right)))
.Return<string>();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With