Skip to content

Instantly share code, notes, and snippets.

@Novakov
Last active August 29, 2015 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Novakov/4dbbe4a6d97a4499ea62 to your computer and use it in GitHub Desktop.
Save Novakov/4dbbe4a6d97a4499ea62 to your computer and use it in GitHub Desktop.
Having fun with collection initializer in C#
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace PatternMatch
{
class Program
{
static void Main(string[] args)
{
var matcher = new Pattern<string, string>
{
{
s => s.StartsWith("S"), s => "String starts with S"
},
{
s => s.StartsWith("E"), s => "String starts with E"
},
s => "Another string"
};
Console.WriteLine(matcher.Match("Start"));
Console.WriteLine(matcher.Match("Ending"));
Console.WriteLine(matcher.Match("Other"));
Console.WriteLine();
Console.WriteLine("Space" | matcher);
Console.WriteLine();
var range = new FuncPredicate<int>(i => 6 <= i && i <= 8);
for (int input = 0; input <= 10; input++)
{
Console.WriteLine(input | new Pattern<int, string>
{
{range, "In range <6,8>"},
{5, "Five"},
{10, i => "Got value of ten! Proof:" + 10},
{i => i%2 == 0, "Odd"},
{i => i%2 == 1, "Even"},
});
}
}
}
public class Pattern<TInput, TOutput> : IEnumerable
{
private readonly List<Tuple<Predicate<TInput>, Func<TInput, TOutput>>> clauses;
public Pattern()
{
this.clauses = new List<Tuple<Predicate<TInput>, Func<TInput, TOutput>>>();
}
public void Add(Predicate<TInput> predicate, Func<TInput, TOutput> action)
{
this.clauses.Add(Tuple.Create(predicate, action));
}
public void Add(Func<TInput, bool> predicate, Func<TInput, TOutput> action)
{
this.Add((Predicate<TInput>)predicate, action);
}
public void Add(Func<TInput, TOutput> defaultAction)
{
this.Add(_ => true, defaultAction);
}
public void Add(Func<TInput, bool> predicate, TOutput value)
{
this.Add(predicate, _ => value);
}
public void Add(Predicate<TInput> predicate, TOutput value)
{
this.Add(predicate, _ => value);
}
public void Add(TOutput value)
{
this.Add(_ => value);
}
public void Add(IEquatable<TInput> sample, Func<TInput, TOutput> value)
{
this.Add(new SamplePredicate<TInput>(sample), value);
}
public void Add(IEquatable<TInput> sample, TOutput value)
{
this.Add(sample, _ => value);
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
public TOutput Match(TInput input)
{
var clause = this.clauses.FirstOrDefault(x => x.Item1.Matches(input));
if (clause != null)
{
return clause.Item2(input);
}
throw new InvalidOperationException("No clause matches");
}
public static TOutput operator |(TInput input, Pattern<TInput, TOutput> pattern)
{
return pattern.Match(input);
}
}
public abstract class Predicate<T>
{
public abstract bool Matches(T value);
public static implicit operator Predicate<T>(Func<T, bool> func)
{
return new FuncPredicate<T>(func);
}
}
public class FuncPredicate<T> : Predicate<T>
{
private readonly Func<T, bool> predicate;
public FuncPredicate(Func<T, bool> predicate)
{
this.predicate = predicate;
}
public override bool Matches(T value)
{
return this.predicate(value);
}
}
public class SamplePredicate<T> : Predicate<T>
{
private readonly IEquatable<T> sample;
public SamplePredicate(IEquatable<T> sample)
{
this.sample = sample;
}
public override bool Matches(T value)
{
return this.sample.Equals(value);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment