プロクシ
RealProxyの話。
///ペア public class Pair : ICloneable { private object _First; ///public object First {get {return _First;} set {_First = value;}} private object _Second; /// public object Second {get {return _Second;} set {_Second = value;}} /// コンストラクタ public Pair(object o1,object o2) {_First = o1; _Second = o2;} ///public sealed override bool Equals(object obj) { Pair p = (Pair)obj; return p != null && _First.Equals(p._First) && _Second.Equals(p._Second); } /// public override int GetHashCode() { return _First.GetHashCode() ^ _Second.GetHashCode(); } /// public override string ToString() { return _First.ToString() + " " + _Second.ToString(); } public object Clone() { return new Pair(_First,_Second); } } /// public interface IHashtable2 { /// インデクサ object this[object o1,object o2] {get; set;} } ///キーが2つのHashtable public class Hashtable2 : Hashtable, IHashtable2 { ///インデクサ public object this[object o1,object o2] { get {return this[new Pair(o1,o2)];} set {this[new Pair(o1,o2)] = value;} } }
例えば、キーは2つのインデクサを持つHashtable2型の h があったとしよう。これにネットワークの2地点間の距離が入っているとする。最初の設計では、ネットワークは無向グラフだったとしよう。地点i1と地点i2の距離がh[i1,i2]で取り出せるとしよう。無向なので、i2からi1の距離は、h[i1,i2]と同じである。メモリの節約からh[i2,i1]には、何も入っていないとする。
あるとき仕様が変わって、ネットワークを有向グラフにしなければいけなくなったとする。
h「i2,i1]=h[i1,i2];をhの構築時にすればいいように思われる。おっと、もう1つの要件で、オリジナルの h(すなわち片方向のデータ)も別途必要というのがあった。では、hを複製しよう。なになに、複製のタイミングが多すぎて、速度とメモリが問題だと。こんなときは、プロクシを使うことができる。
///public class DualHashTable2 : RealProxy { private IHashtable2 org; /// public DualHashTable2(IHashtable2 h) : base(typeof(IHashtable2)) {org = h;} /// public override IMessage Invoke(IMessage msg) { IMethodCallMessage mm = msg as IMethodCallMessage; MethodInfo mi = org.GetType().GetMethod(mm.MethodName,(Type)mm.MethodSignature); object res = mi.Invoke(org,mm.Args); if (res == null && mm.InArgCount == 3 && mm.MethodName == "set_Item") res = mi.Invoke(org,new object{mm.Args[1],mm.Args[0],mm.Args[2]}); return new ReturnMessage(res,null,0,mm.LogicalCallContext,mm); } } IHashtable2 h = new DualHashTable2(original).GetTransparentProxy() as IHashtable2;
例えば、こんな感じに。対象がインターフェースかMarshalByRefObjectでないといけないのがネックだが。
VG.netいいなぁ。私は、デザインセンスないんだけどね。