A minap olvastam egy cikket egy jópofa hackről, amivel olyan szavakat is tudunk infix operátorként használni, amik amúgy nem overrideolható operátorok az adott nyelvben. A cikk pythonról szól, de nekem úgy tűnt, hogy bármilyen operator overloadingra képes nyelvben megoldható, ezért leporoltam a Visual Studiot, és a sok a Java után operator overloadoltam egy kicsit C#-ban.

Először a tesztet mutatom, amiből igaziból nyilvánvaló is, hogy mi a hack lényege:

using Xunit;

namespace Kodfodrasz.Infix.Test {

    public class InfixTest {
        [Fact]
        public void AddOperatorTest() {
            var add = new Infix.Infix<int, int, int>((a, b) => a + b);

            var result = 3 | add | 4;

            Assert.Equal(7, result);
        }
    }
}

Igen, a | operátor egy típuson értelmezve indítja a műveletet, illetve befejezi azt. A műveletet egy változóban lehet tárolni.

Hack? Igen!
Szép? Nem!
Jópofa ötlet? Igen!

És akkor egy lehetséges megvalósítás:

using System;

namespace Kodfodrasz.Infix {

    public class Infix<TLeft, TRight, TResult> {
        public Func<TLeft, TRight, TResult> operation;

        public Infix(Func<TLeft, TRight, TResult> operation) {
            this.operation = operation;
        }

        public static InfixHalfApplied<TLeft, TRight, TResult> operator |(TLeft left, Infix<TLeft, TRight, TResult> infix) {
            return new InfixHalfApplied<TLeft, TRight, TResult>(infix, left);
        }

        public class InfixHalfApplied<TLeft, TRight, TResult> {
            private Infix<TLeft, TRight, TResult> infix;
            private TLeft left;

            internal InfixHalfApplied(Infix<TLeft, TRight, TResult> infix, TLeft left) {
                this.infix = infix;
                this.left = left;
            }

            public static TResult operator |(InfixHalfApplied<TLeft, TRight, TResult> infixHalfApplied, TRight right) {
                return infixHalfApplied.infix.operation(infixHalfApplied.left, right);
            }
        }
    }
}

Igen, az inner class lehetne outer is, illetve ha már inner lehetnének a típusparamétereinek nevei mások, mert így (jogosan) warningol, de nekem így is megfelel, így talán szemléletesebb is. Amellett az is látható, hogy ezek az operátorok így nem tudnak polimorfikusak lenni, legfeljebb a C# 5 dynamic támogatásával. A Python verzióban persze ez az alap viselkedés.

Bár nem tudok olyan helyzetet elképzelni amiben ezt egy igazi projektben használnám, szerintem egész érdekes, és jó tudni, hátha az élet rácáfol erre az előítéletemre.