JUGEMテーマ:
コンピュータSource and Project今回は、RealProxyが全部、クライアントに答えちゃうという実装をしたいと思います。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
namespace Art55.ProxyDemo20121212_001
{
public class MyProxy : RealProxy, IRemotingTypeInfo
{
static MyProxy()
{
OperationSet = new Dictionary<string, Func<double, double, double>>
{
{"Add", (x, y) => x + y},
{"Multiply", (x, y) => x*y},
};
}
private static readonly Dictionary<string, Func<double, double, double>> OperationSet;
public MyProxy()
: base(typeof(MarshalByRefObject))
{
}
public override IMessage Invoke(IMessage msg)
{
var callMessage = (IMethodCallMessage)msg;
if (OperationSet.ContainsKey(callMessage.MethodName))
{
object reusltValue = OperationSet[callMessage.MethodName]((double)callMessage.Args[0],
(double)callMessage.Args[1]);
return new ReturnMessage(reusltValue, null, 0, null, callMessage);
}
return new ReturnMessage(new NotImplementedException(), callMessage);
}
public bool CanCastTo(Type fromType, object o)
{
if (OperationSet
.Keys
.Any(key => fromType.GetMethod(key) == null))
{
return false;
}
var methodInfos = OperationSet
.Keys
.Select(fromType.GetMethod)
.ToList();
if (methodInfos
.Any(m => m.ReturnType != typeof(double)))
{
return false;
}
return methodInfos
.Select(m => m.GetParameters())
.All(para => para.Length == 2
&& para[0].ParameterType == typeof (double)
&& para[1].ParameterType == typeof (double));
}
public string TypeName { get; set; }
}
}
RealProxyの実装は、こんな感じです。Invokeメソッドが呼び出されると、あらかじめ定義しておいたメソッドAddやMultiplyのオペレーションを実行します。今回は、IRemotingTypeInfoインターフェイスも実装しまいた。
IRemotingTypeInfo.CanCastToメソッドを実装することで、対応する透過プロキシがキャスト可能かどうか判定してくれます。OperationSetのValueとチェックロジックが2重管理になっているのは、すこし力量不足感がただよっていますが、とりあえず実装してみました。
これをクライアントで使って見ると
using System;
namespace Art55.ProxyDemo20121212_001
{
class Program
{
static void Main()
{
var realProxy = new MyProxy();
var calculator = (ICalculator) realProxy.GetTransparentProxy();
Console.WriteLine(calculator.Add(10, 11));
Console.WriteLine(calculator.Multiply(10, 11));
var calculator2 = (ICalculator2)realProxy.GetTransparentProxy();
Console.WriteLine(calculator2.Add(20, 21));
Console.WriteLine(calculator2.Multiply(20, 21));
}
}
public interface ICalculator
{
double Add(double x, double y);
double Multiply(double x, double y);
}
public interface ICalculator2
{
double Add(double x, double y);
double Multiply(double x, double y);
}
}
ICalculatorインターフェイスやICalculator2インターフェイスと、全くキャストできそうにもないインターフェイスをキャストして実行するコードが書けている事がわかります。もちろん、コンパイルは、継承関係になくても書けるわけですが、これを実行すると
21
110
41
420
と出力され、実行時に継承関係にないICalculatorインターフェイスやICalculator2インターフェイスでキャストして、メソッドが呼び出せていることが確認できます。もちろん「=」をオーバーライドしているわけでもないのは自明ですね。.NETの世界って不思議。
Source and Project