Никогда не возникало желания добавить в C# свой оператор? Или добавить бинарный оператор над встроенными типами, например…
Идея не нова, синтаксис подсмотрен в Хаскеле. И достаточно много boilerplate code. Но как DSL – вроде красиво.
Надо подумать, что с этим можно сделать и как можно более красиво конвертировать ф-и в операторы.
Использование:
private static void ArithmeticExample()
{
Func<int, int, int> _sum = (a, b) => a + b;
Func<int, int, int> _mult = (a, b) => a * b;
var sum = _sum.Infixize();
var mult = _mult.Infixize();
Console.WriteLine(1 |sum| (2 |mult| 4) |sum| 8); //17
}
private static void PoorMansLINQ()
{
Predicate<int> odd = x => x % 2 != 0;
// why the type inference is unable to do this?
Func<IEnumerable<int>, Predicate<int>, IEnumerable<int>> _where = Where;
var where = _where.Infixize();
Func<IEnumerable<int>, Func<int, int>, IEnumerable<int>> _Map = Map;
var perform = _Map.Infixize();
Func<IEnumerable<int>, IEnumerable<int>, IEnumerable<int>> _Join = Join;
var join = _Join.Infixize();
Func<IEnumerable<int>, IEnumerable<int>, IEnumerable<int>> _Intersect = Intersect;
var intersect = _Intersect.Infixize();
foreach (var x in Enumerable.Range(0, 10)
|where| odd |perform| SideEffectPrint) ; // 1 3 5 7 9
Console.WriteLine();
foreach (var x in
Enumerable.Range(0, 5) |join| Enumerable.Range(10, 5) |intersect| Enumerable.Range(3,10)
|perform| SideEffectPrint) ; //3 4 10 11 12
Console.ReadLine();
}
Реализация:
public static class InfixExtensions
{
public static InfixOperator<T1, T2, RT> Infixize<T1,T2,RT>(this Func<T1, T2, RT> f)
{
return new InfixOperator<T1, T2, RT>(f);
}
}
/// <summary>
/// TODO: Curryable Infix Operator
/// </summary>
/// <typeparam name="T1">Left operand type</typeparam>
/// <typeparam name="T2">Right operand type</typeparam>
/// <typeparam name="RT">Return type</typeparam>
public class InfixOperator<T1,T2,RT>
{
Func<T1, T2, RT> function;
T1 leftvalue;
public InfixOperator(Func<T1,T2,RT> f)
{
this.function = f;
}
public InfixOperator(T1 lv, Func<T1, T2, RT> f)
{
this.function = f;
this.leftvalue = lv;
}
public static RT operator |(InfixOperator<T1,T2,RT> a, T2 b)
{
return a.function(a.leftvalue, b);
}
public static InfixOperator<T1,T2,RT> operator |(T1 a, InfixOperator<T1,T2,RT> b)
{
return new InfixOperator<T1,T2,RT>(a, b.function);
}
}