TypeMatch (邪悪です)
先週末の名古屋 Scala 勉強会用に、こんなコードを書きました。
2 行目からの ObjectExtension クラスで、object に対して拡張メソッドを追加しています*1。
このときは Cast という名前にしましたが、これは TypeMatch という名前にして、
e.TypeMatch( (Var v) => v.ToString(), (Number n) => n.ToString(), (UnOp u) => u.Operator != "-" ? u.ToString() : u.Arg.TypeMatch( (UnOp uu) => uu.Operator == "-" ? uu.Arg.ToString() : string.Format("-({0})", uu), () => u.ToString() ), (BinOp b) => b.ToString() )
と書いたほうがそれっぽいですね。
後はいつもどおり、T4 Template で自動生成すれば OK です。
以下その例です。
<#@ template inherits="Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation" language="C#v3.5" debug="true" hostSpecific="true" #> <#@ output extension=".cs" encoding="UTF-8" #> <#@ Assembly Name="System.dll" #> <#@ Assembly Name="System.Core.dll" #> <#@ Assembly Name="System.Windows.Forms.dll" #> <#@ import namespace="System" #> <#@ import namespace="System.IO" #> <#@ import namespace="System.Diagnostics" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Collections" #> <#@ import namespace="System.Collections.Generic" #> <# int n = 10; #> using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace CommonsSharp.Lang { /// <summary> /// objectの拡張メソッド群です。 /// </summary> public static class ObjectExtension { <# for (int i = 1; i <= n; i++) { var range = Enumerable.Range(1, i); var types = range.Select(j => "T" + j).ToArray(); var args1 = range.Select(j => string.Format("Action<T{0}> ifT{0}", j)).ToArray(); var args2 = range.Select(j => string.Format("Func<T{0}, TResult> ifT{0}", j)).ToArray(); var typeParam = string.Join(", ", types); var actParam = string.Join(", ", args1); var funcParam = string.Join(", ", args2); #> public static void TypeMatch<<#= typeParam #>>(this object self, <#= actParam #>) { if (self is T1) { ifT1((T1)self); return; } <# for (int j = 2; j <= i; j++) { #> else if (self is T<#= j #>) { ifT<#= j #>((T<#= j #>)self); return; } <# } #> throw new Exception(); } public static void TypeMatch<<#= typeParam #>>(this object self, <#= actParam #>, Action otherwise) { if (self is T1) ifT1((T1)self); <# for (int j = 2; j <= i; j++) { #> else if (self is T<#= j #>) ifT<#= j #>((T<#= j #>)self); <# } #> else otherwise(); } public static TResult TypeMatch<<#= typeParam #>, TResult>(this object self, <#= funcParam #>) { if (self is T1) return ifT1((T1)self); <# for (int j = 2; j <= i; j++) { #> else if (self is T<#= j #>) return ifT<#= j #>((T<#= j #>)self); <# } #> throw new Exception(); } public static TResult TypeMatch<<#= typeParam #>, TResult>(this object self, <#= funcParam #>, Func<TResult> otherwise) { if (self is T1) return ifT1((T1)self); <# for (int j = 2; j <= i; j++) { #> else if (self is T<#= j #>) return ifT<#= j #>((T<#= j #>)self); <# } #> return otherwise(); } <# } #> } }