Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
using System;
namespace Tonari.ActionPattern
{
public static class SwitchPattern
{
public static CaseBase<T> Switch<T>(T value)
{
return new CaseBaseCore<T>(value);
}
public static CaseBase<T, TResult> SelectSwitch<T, TResult>(T value)
{
return new CaseBaseCore<T, TResult>(value);
}
private class CaseBaseCore<T> : CaseBase<T>
{
public CaseBaseCore(T value) : base(value) { }
public override CaseBase<T> Case(T value, Action<T> action)
{
if (value.Equals(Value))
{
action(Value);
return BreakCase<T>.DefaultValue;
}
return this;
}
public override CaseBase<T> Case(Func<T, bool> predicate, Action<T> action)
{
if (predicate(Value))
{
action(Value);
return BreakCase<T>.DefaultValue;
}
return this;
}
public override CaseBase<T> Case<TTargetType>(Action<TTargetType> action)
{
if (typeof(TTargetType).IsAssignableFrom(typeof(T)))
{
var a = action as Action<T>;
if (a == null)
{
throw new InvalidCastException("A value type cannot be casted.");
}
a(Value);
return BreakCase<T>.DefaultValue;
}
return this;
}
public override CaseBase<T> Case<TTargetType>(TTargetType value, Action<TTargetType> action)
{
if (typeof(TTargetType).IsAssignableFrom(typeof(T)))
{
var a = action as Action<T>;
if (a == null)
{
throw new InvalidCastException("A value type cannot be casted.");
}
if (value.Equals(Value))
{
a(Value);
return BreakCase<T>.DefaultValue;
}
}
return this;
}
public override CaseBase<T> Case<TTargetType>(Func<TTargetType, bool> predicate, Action<TTargetType> action)
{
if (typeof(TTargetType).IsAssignableFrom(typeof(T)))
{
var p = predicate as Func<T, bool>;
var a = action as Action<T>;
if (p == null || a == null)
{
throw new InvalidCastException("A value type cannot be casted.");
}
if (p(Value))
{
a(Value);
return BreakCase<T>.DefaultValue;
}
}
return this;
}
public override void Default(Action<T> action)
{
action(Value);
}
}
private class CaseBaseCore<T, TResult> : CaseBase<T, TResult>
{
public CaseBaseCore(T value) : base(value, default(TResult)) { }
public override CaseBase<T, TResult> Case(T value, Func<T, TResult> action)
{
if (value.Equals(Value))
{
return new ReturnCase<T, TResult>(action(Value));
}
return this;
}
public override CaseBase<T, TResult> Case(Func<T, bool> predicate, Func<T, TResult> action)
{
if (predicate(Value))
{
return new ReturnCase<T, TResult>(action(Value));
}
return this;
}
public override CaseBase<T, TResult> Case<TTargetType>(Func<TTargetType, TResult> action)
{
if (typeof(TTargetType).IsAssignableFrom(typeof(T)))
{
var a = action as Func<T, TResult>;
if (a == null)
{
throw new InvalidCastException("A value type cannot be casted.");
}
return new ReturnCase<T, TResult>(a(Value));
}
return this;
}
public override CaseBase<T, TResult> Case<TTargetType>(TTargetType value, Func<TTargetType, TResult> action)
{
if (typeof(TTargetType).IsAssignableFrom(typeof(T)))
{
var a = action as Func<T, TResult>;
if (a == null)
{
throw new InvalidCastException("A value type cannot be casted.");
}
if (value.Equals(Value))
{
return new ReturnCase<T, TResult>(a(Value));
}
}
return this;
}
public override CaseBase<T, TResult> Case<TTargetType>(Func<TTargetType, bool> predicate, Func<TTargetType, TResult> action)
{
if (typeof(TTargetType).IsAssignableFrom(typeof(T)))
{
var p = predicate as Func<T, bool>;
var a = action as Func<T, TResult>;
if (p == null || a == null)
{
throw new InvalidCastException("A value type cannot be casted.");
}
if (p(Value))
{
return new ReturnCase<T, TResult>(a(Value));
}
}
return this;
}
public override TResult Default(Func<T, TResult> action)
{
return action(Value);
}
}
private class BreakCase<T> : CaseBase<T>
{
public static readonly CaseBase<T> DefaultValue = new BreakCase<T>();
private BreakCase() : base(default(T))
{
}
public override CaseBase<T> Case(T value, Action<T> action)
{
return DefaultValue;
}
public override CaseBase<T> Case(Func<T, bool> predicate, Action<T> action)
{
return DefaultValue;
}
public override CaseBase<T> Case<TTargetType>(Action<TTargetType> action)
{
return DefaultValue;
}
public override CaseBase<T> Case<TTargetType>(TTargetType value, Action<TTargetType> action)
{
return DefaultValue;
}
public override CaseBase<T> Case<TTargetType>(Func<TTargetType, bool> predicate, Action<TTargetType> action)
{
return DefaultValue;
}
public override void Default(Action<T> action) { }
}
private class ReturnCase<T, TResult> : CaseBase<T, TResult>
{
public static readonly CaseBase<T, TResult> DefaultValue = new ReturnCase<T, TResult>(default(TResult));
public ReturnCase(TResult result) : base(default(T), result) { }
public override CaseBase<T, TResult> Case(T value, Func<T, TResult> action)
{
return this;
}
public override CaseBase<T, TResult> Case(Func<T, bool> predicate, Func<T, TResult> action)
{
return this;
}
public override CaseBase<T, TResult> Case<TTargetType>(Func<TTargetType, TResult> action)
{
return this;
}
public override CaseBase<T, TResult> Case<TTargetType>(TTargetType value, Func<TTargetType, TResult> action)
{
return this;
}
public override CaseBase<T, TResult> Case<TTargetType>(Func<TTargetType, bool> predicate, Func<TTargetType, TResult> action)
{
return this;
}
public override TResult Default(Func<T, TResult> action)
{
return Result;
}
}
}
public abstract class CaseBase<T>
{
protected T Value { get; private set; }
protected CaseBase(T value)
{
Value = value;
}
public abstract CaseBase<T> Case(T value, Action<T> action);
public abstract CaseBase<T> Case(Func<T, bool> predicate, Action<T> action);
public abstract CaseBase<T> Case<TTargetType>(Action<TTargetType> action);
public abstract CaseBase<T> Case<TTargetType>(TTargetType value, Action<TTargetType> action);
public abstract CaseBase<T> Case<TTargetType>(Func<TTargetType, bool> predicate, Action<TTargetType> action);
public abstract void Default(Action<T> action);
}
public abstract class CaseBase<T, TResult>
{
protected T Value { get; private set; }
protected TResult Result{ get; private set; }
protected CaseBase(T value, TResult result)
{
Value = value;
Result = result;
}
public abstract CaseBase<T, TResult> Case(T value, Func<T, TResult> action);
public abstract CaseBase<T, TResult> Case(Func<T, bool> predicate, Func<T, TResult> action);
public abstract CaseBase<T, TResult> Case<TTargetType>(Func<TTargetType, TResult> action);
public abstract CaseBase<T, TResult> Case<TTargetType>(TTargetType value, Func<TTargetType, TResult> action);
public abstract CaseBase<T, TResult> Case<TTargetType>(Func<TTargetType, bool> predicate, Func<TTargetType, TResult> action);
public abstract TResult Default(Func<T, TResult> action);
public static implicit operator TResult(CaseBase<T, TResult> original)
{
return original.Result;
}
}
}
Owner

yKimisaki commented Feb 5, 2016

using static Tonari.ActionPattern.SwitchPattern;
using static System.Console;

namespace ConsoleApplication4
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            WhatIs(5);
            WhatIs(10);
            WhatIs("5");
            WhatIs(5f);
        }

        private static void WhatIs<T>(T value)
        {
            Switch(value)
                .Case<int>(x => x % 2 == 1, x => WriteLine("奇数の整数"))
                .Case<int>(x => WriteLine("偶数の整数"))
                .Case<string>(x => WriteLine("文字列"))
                .Default(x => WriteLine("その他"));
        }
    }
}
Owner

yKimisaki commented Feb 8, 2016

private static string WhatIs2<T>(T value)
{
    return SelectSwitch<T, string>(value)
        .Case<int>(x => "偶数")
        .Case<int>(x => "整数")
        .Case<float>(x => "浮動小数")
        .Case<IComparable>(x => "比較")
        .Default(x => "その他");
}

みたいに特定の型に変換できるようにした。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment