最近在做RPC的时候遇到了一点问题,接口I的调用方在进程A,而实现方在进程B。那么要完成进程A中的操作,必然要在进程A生成接口I的动态代理。怎么办呢?这里使用DispatchProxy
来进行实现
DispatchProxy
是一个抽象类,使用方法非常简单。只需要继承这个类,重写他的Invoke
方法,这里我们可以从参数获得代理被调用方法的MethodInfo
以及其传入的参数。这里我们先试着打印他的方法名称
public class ADispatchProxy : DispatchProxy
{
protected override object Invoke(MethodInfo targetMethod, object[] args)
{
Console.WriteLine(targetMethod.Name);
return null;
}
}
接着我们考虑接口IA
public interface IA
{
void Foo(string a);
}
试着创建一个IA的代理,这里用到了静态方法DispatchProxy.Create<IA, ADispatchProxy>()
class Program
{
static void Main(string[] args)
{
var a = DispatchProxy.Create<IA, ADispatchProxy>();
a.Foo("123");
}
}
OK,我们通过一个动态代理完成了接口的调用。
那么现在我们再试着通过容器注入一个实现。这里是通过ConcurrentDictionary
做的简单容器
/// <summary>
/// 用于模块内部使用的IOC容器
/// </summary>
internal class Container
{
private static readonly Lazy<Container> Instance = new Lazy<Container>();
public static Container Current => Instance.Value;
private readonly ConcurrentDictionary<Type, object> _dictionary = new ConcurrentDictionary<Type, object>();
/// <summary>
/// 向容器中添加对象。
/// </summary>
/// <typeparam name="T">对象的指定类型。</typeparam>
/// <param name="value">向容器中添加的对象实例。</param>
public void Set<T>(T value)
{
_dictionary[typeof(T)] = value;
}
/// <summary>
/// 从容器中获取指定类型的对象实例。
/// </summary>
/// <typeparam name="TService">指定类型。</typeparam>
/// <returns>容器中指定类型的对象实例。</returns>
public TService Get<TService>()
{
var type = typeof(TService);
return (TService) Get(type);
}
/// <summary>
/// 从容器中获取指定类型的对象实例。
/// </summary>
/// <typeparam name="TService">指定类型。</typeparam>
/// <returns>容器中指定类型的对象实例。</returns>
public object Get(Type type)
{
if (_dictionary.TryGetValue(type, out var value))
{
return value;
}
return null;
}
}
而在调用端代码更改如下,我们向容器中注入IA的实现A,并且在ADispatchProxy的invoke方法中获取实例,进行调用
class Program
{
static void Main(string[] args)
{
Container.Current.Set<IA>(new A());
var a = DispatchProxy.Create<IA, ADispatchProxy>();
a.Foo("123");
}
}
public interface IA
{
void Foo(string a);
}
public class A : IA
{
public void Foo(string a)
{
Console.WriteLine(a);
}
}
public class ADispatchProxy : DispatchProxy
{
protected override object Invoke(MethodInfo targetMethod, object[] args)
{
var type = targetMethod.DeclaringType;
var o = Container.Current.Get(type);
if (o != null)
{
Console.WriteLine(targetMethod.Name);
return targetMethod.Invoke(o, args);
}
return null;
}
}
可以看到在动态代理中完成了实例方法的调用。我们之后再将参数信息通过IPC传递给进程B,就可以实现RPC了。
参考链接:
本文会经常更新,请阅读原文: https://xinyuehtx.github.io/post/%E4%BD%BF%E7%94%A8DispatchProxy%E7%94%9F%E6%88%90%E4%BB%A3%E7%90%86.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名黄腾霄(包含链接: https://xinyuehtx.github.io ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 。