プロクシ

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いいなぁ。私は、デザインセンスないんだけどね。