C#でデコレーター風味でメモ化を実装してみました。
デコレーターをC#で実装しようとやっていた際に思いついたのでここに置いておきます。
メモ化とは
重い計算をする際によく用いられます。
同じ引数だと同様の結果を返すような場合、二回目も三回目も同様に計算を行うのは処理時間の都合上非常に無駄です。
なので、引数と戻り値のリストを作成しておいてリストにある引数が渡された場合計算をせずにリストから結果を渡すというものです。
実装方法
Dictionaryで計算結果を保持して引数が存在するかの比較を行います。
今回は以下のように実装しました。
計算を行うメソッドはこのように記述しました。
publiclongDecorate_square(longx){returnx*x;}今回は簡単に二乗を行うメソッドです。
そして実行を代行するメソッドはこちらです。
publiclongsquare(longsx2){Func<long,long>f=Decorate_square;Decorator.memo<long,long>memo=newDecorator.memo<long,long>();returnmemo.Invoke(data,f,sx2);}Funcでメソッドを変数にいれてメモ化のメソッドの型を指定してメモ化のメソッド経由で実行します。
そして、メモ化を行うメソッドはこのように実装しました。
usingSystem;usingSystem.Collections.Generic;usingSystem.Reflection;publicclassDecorator{publicDictionary<object,object>data=newSystem.Collections.Generic.Dictionary<object,object>();publicclassmemo<arg01,ans>{publicansInvoke(Dictionary<object,object>data,Func<arg01,ans>f,objectx){if(data.ContainsKey((arg01)x)){Console.WriteLine("-O-");return(ans)data[(arg01)x];}else{Console.WriteLine("-X-");ansres=(ans)(object)f((arg01)x);data[(arg01)x]=res;returnres;}}}}これらを書くのは面倒では。。。
はい、その通りです。
そこでRoslynのVisualStudio拡張機能の修正機能です。
私の別の記事で書きましたがこれはソースコード自体を自動で書き換えることができます。
なので、[memo]などと記述した際に自動でデコレーターメソッドを記述できるようになると非常に良いです。
全コード
generic.cs
usingSystem;usingSystem.Collections.Generic;usingSystem.Reflection;publicclassdeco2:Decorator{publiclongsquare(longsx2){Func<long,long>f=Decorate_square;Decorator.memo<long,long>memo=newDecorator.memo<long,long>();returnmemo.Invoke(data,f,sx2);}publiclongDecorate_square(longx){returnx*x;}}memo_decorator.cs
usingSystem;usingSystem.Collections.Generic;usingSystem.Reflection;publicclassDecorator{publicDictionary<object,object>data=newSystem.Collections.Generic.Dictionary<object,object>();publicclassmemo<arg01,ans>{publicansInvoke(Dictionary<object,object>data,Func<arg01,ans>f,objectx){if(data.ContainsKey((arg01)x)){Console.WriteLine("-O-");return(ans)data[(arg01)x];}else{Console.WriteLine("-X-");ansres=(ans)(object)f((arg01)x);data[(arg01)x]=res;returnres;}}}}以下は実行部分です
Program.cs
namespacetwice_arg_memo{classProgram{staticvoidMain(string[]args){deco2d=newdeco2();Console.WriteLine(d.square(2));Console.WriteLine(d.square(2));Console.WriteLine(d.square(3));Console.WriteLine(d.square(4));Environment.Exit(0);}}}