Καλησπέρα φιλε Άγγελε, περιττό να αναφέρω ότι χαίρομαι ιδιαιτερα που ασχολείσαι με F# και FP γενικότερα. Στα δικά μου C# projects χρησιμοποιώ αρκετά Pattern Matching και έχω υλοποιήσει κάτι που πιστεύω ότι θα το βρείς ενδιαφέρον...
Υλικά κατασκευής:
Μια abstract class για την απαραίτητη αφαίρεση από την πραγματικότητα.
public abstract class PatternMatch<TMatchValue, TResult>
{
private readonly Predicate<TMatchValue> predicateFunc;
private readonly Func<TMatchValue, TResult> resultFunc;
private readonly PatternMatch<TMatchValue, TResult> linkPatternMatch;
public PatternMatch(Predicate<TMatchValue> predicateFunc, Func<TMatchValue, TResult> resultFunc)
: this(predicateFunc, resultFunc, null)
{
}
public PatternMatch(Predicate<TMatchValue> predicateFunc, Func<TMatchValue, TResult> resultFunc, PatternMatch<TMatchValue, TResult> linkPatternMatch)
{
if (predicateFunc == null) throw new ArgumentNullException("predicateFunc");
if (resultFunc == null) throw new ArgumentNullException("resultFunc");
this.predicateFunc = predicateFunc;
this.resultFunc = resultFunc;
this.linkPatternMatch = linkPatternMatch;
}
public Predicate<TMatchValue> PredicateFunc { get { return predicateFunc; } }
public Func<TMatchValue, TResult> ResultFunc { get { return resultFunc; } }
#region Match
public TResult Match(TMatchValue value)
{
foreach (PatternMatch<TMatchValue, TResult> patternMatch in FromRootToBottom(this))
{
if (patternMatch.PredicateFunc(value))
return patternMatch.ResultFunc(value);
}
throw new MatchNotFoundException(String.Format("Incomplete pattern match, match value {0}", value));
}
private IEnumerable<PatternMatch<TMatchValue, TResult>> FromRootToBottom(PatternMatch<TMatchValue, TResult> patternMatch)
{
if (patternMatch.linkPatternMatch == null)
yield return patternMatch;
else {
foreach (PatternMatch<TMatchValue, TResult> enumeratedPatternMatch in FromRootToBottom(patternMatch.linkPatternMatch))
yield return enumeratedPatternMatch;
yield return patternMatch;
}
}
#endregion
}
Κάποιες απλές και ταπεινές concrete classes για τις διαφορες περιπτώσεις
public class WithPatternMatch<TMatchValue, TResult> : PatternMatch<TMatchValue, TResult>
{
public WithPatternMatch(Predicate<TMatchValue> predicateFunc, Func<TMatchValue, TResult> resultFunc)
: this(predicateFunc, resultFunc, null)
{
}
public WithPatternMatch(Predicate<TMatchValue> predicateFunc, Func<TMatchValue, TResult> resultFunc, PatternMatch<TMatchValue, TResult> linkPatternMatch)
: base(predicateFunc, resultFunc, linkPatternMatch)
{
}
}
public class ElsePatternMatch<TMatchValue, TResult> : PatternMatch<TMatchValue, TResult>
{
public ElsePatternMatch(Func<TMatchValue, TResult> resultFunc, PatternMatch<TMatchValue, TResult> linkPatternMatch)
: base(value => true, resultFunc, linkPatternMatch)
{
}
}
Αλλη μια ταπεινή class για τα Incompete matches
public class MatchNotFoundException : Exception
{
public MatchNotFoundException(string message) : base(message) { }
}
Και μια static class για bootstrap και extension methods για fluent style
public static class PatternMatch
{
#region With
public static WithPatternMatch<TMatchValue, TResult> With<TMatchValue, TResult>(this WithPatternMatch<TMatchValue, TResult> patternMatch, Predicate<TMatchValue> predicateFunc, Func<TMatchValue, TResult> resultFunc)
{
return new WithPatternMatch<TMatchValue, TResult>(predicateFunc, resultFunc, patternMatch);
}
public static WithPatternMatch<TMatchValue, TResult> With<TMatchValue, TResult>(Predicate<TMatchValue> predicateFunc, Func<TMatchValue, TResult> resultFunc)
{
return With(null, predicateFunc, resultFunc);
}
public static WithPatternMatch<TMatchValue, TResult> With<TMatchValue, TResult>(this WithPatternMatch<TMatchValue, TResult> patternMatch, Predicate<TMatchValue> predicateFunc, Func<TResult> resultFunc)
{
return With(patternMatch, predicateFunc, value => resultFunc());
}
public static WithPatternMatch<TMatchValue, TResult> With<TMatchValue, TResult>(Predicate<TMatchValue> predicateFunc, Func<TResult> resultFunc)
{
return With(null, predicateFunc, resultFunc);
}
#endregion
#region Else
public static ElsePatternMatch<TMatchValue, TResult> Else<TMatchValue, TResult>(this WithPatternMatch<TMatchValue, TResult> patternMatch, Func<TMatchValue, TResult> resultFunc)
{
return new ElsePatternMatch<TMatchValue, TResult>(resultFunc, patternMatch);
}
public static ElsePatternMatch<TMatchValue, TResult> Else<TMatchValue, TResult>(this WithPatternMatch<TMatchValue, TResult> patternMatch, Func<TResult> resultFunc)
{
return Else(patternMatch, value => resultFunc());
}
#endregion
}
Τα ανακατεύουμε καλά και ορίστε το αποτέλεσμα
var pattern =
PatternMatch.With<int, string>(value => value == 1, value => "One ")
.With(value => value == 2, value => "Two ")
.With(value => value == 3, value => "Three ")
.Else(() => "Else");
Console.WriteLine(pattern.Match(4));
Palladinos Nick
Software Engineer
-----------------------
The limits of my language mean the limits of my world. (Ludwig Wittgenstein)