デザインパターンの1つであるNull Objectパターンのサンプルです。JavaやC#で素直に実装したらクラス毎に用意することになりますがRealProxyを使うことによって、たった一つの実装で全てのクラスに対応します。実はこのネタ、@ITの会議室に出したヤツなのですが全然相手にされませんでした(笑)。折角なのでSingletonにしたり、WeakReferenceを使ったり、ちょっと機能アップしてます。
// ProxyによるNullオブジェクトパターン
using System;
using System.Collections;
using System.Runtime.Remoting.Proxies;
using System.Runtime.Remoting.Messaging;
using System.Reflection;
class NullProxy : RealProxy {
private static Hashtable hash = new Hashtable();
private NullProxy(Type t) : base(t) {}
/// <summary>
/// メソッド呼び出しに割り込んで何もしないで抜ける。
/// メソッドに戻り値がある場合、参照型ならnull、値型なら初期値を返す。
/// </summary>
/// <param name="msg">メッセージ通信オブジェクト</param>
/// <returns>ReturnMessageオブジェクト</returns>
public override IMessage Invoke(IMessage msg) {
IMethodCallMessage req = msg as IMethodCallMessage;
object o = null;
Type t = ((MethodInfo)req.MethodBase).ReturnType;
if (t != typeof(void))
o = Activator.CreateInstance(t);
ReturnMessage rm = new ReturnMessage
(o, null, 0, req.LogicalCallContext, req);
return rm;
}
// 型毎にインスタンスは一つしか作らない
public static object GetInstance(Type t) {
lock (typeof(NullProxy)) {
NullProxy result = null;
// WeakReferenceを使ってGCをじゃましない
WeakReference w = hash[t] as WeakReference;
if (w != null)
result = w.Target as NullProxy;
if (result == null) {
result = new NullProxy(t);
hash[t] = new WeakReference(result);
}
// 透過プロキシを返す
return result.GetTransparentProxy();
}
}
}
// テストクラス
class MyClass : MarshalByRefObject {
public void Sub(int x, ref int y, out int z) {
y = x * 10;
z = x * 100;
}
public int Function() {
return 100;
}
}
interface MyInterface {
void Method();
}
class MyApp
{
static void Main(string[] args)
{
MyInterface mi = NullProxy.GetInstance(typeof(MyInterface)) as MyInterface;
mi.Method();
Random r = new Random();
for (int i = 0; i < 100; ++i) {
int y = 10;
int z = 20;
// 初期値をNullObjectとする
MyClass my = NullProxy.GetInstance(typeof(MyClass)) as MyClass;
if (r.Next() % 2 == 0) {
my = new MyClass();
}
// myの生成がされなくても、構わずメソッドを呼ぶ
my.Sub(i, ref y, out z);
Console.WriteLine("Sub: y = {0}, z = {1}", y, z);
Console.WriteLine("Function: " + my.Function().ToString());
}
}
}