• 基于AppDomain的插件开发由接口定义回调执行域(五)


    前面已经实现了插件的自动加载,调用者拿到插件实例后,如果要调用含有Action或者Func<T>参数的方法时,需要思考"我这个回调应该在哪个域执行呢?"如下:

    //应该是这样?

    Debug.Print("Return => {0}",lastLoadedPlugin.Run(DateTime.Now.ToString(),

    new Action(() => { Debug.Print(AppDomain.CurrentDomain.FriendlyName); })));

    //还是应该这样

    Debug.Print("Return => {0}",lastLoadedPlugin.Run(DateTime.Now.ToString(),

    new Action(() => { Debug.Print(AppDomain.CurrentDomain.FriendlyName); }).CreateRemoteAppDomainProxy()));

    得思考:CreateRemoteAppDomainProxy是不是应该被调用?

    仔细想想,貌似应该在哪个域里执行,应该在接口定义时定义好以避免混乱。如下面定义一个接口:

    public interface IPlugin

    {

    Guid PluginId { get; }

    string Run(string args);

    string Run(string args, [CallerDomainRun] Action action);

    string Run(string args, [CallerDomainRun] Func<string> func);

    }

    "CallerDomainRun"表示此回调应该在调用者域里执行。

    要达到上述目的,我们需要改动 Emit生成代理类的代理,依参数是不是具有 CallerDomainRun ,选择性的生成含有或者不含有"RemoteActionProxy.CreateProxyAction(action)"的代码。如下面所示生成样本:

    public class XXXXXXX_Proxy : IPlugin

    {

    private Func<IPlugin> target;

    public Guid PluginId

    {

    get { return target().PluginId; }

    }

    public string Run(string args)

    {

    return target().Run(args);

    }

    public string Run(string args, Action action)

    {

    return target().Run(args, RemoteActionProxy.CreateProxyAction(action));

    }

    public string Run(string args, Func<string> func)

    {

    return target().Run(args, RemoteFuncProxy<string>.CreateProxyFunc(func));

    }

    }

    附:修改后的EMIT代码如下:

    public static Type CreateFuncProxyType(Type targetType, Type baseType, bool igoreCrossDomainAttribute = false)

    {

    。。。

    var methodBuilder = typeBuilder.DefineMethod(mi.Name, methodAttrs, CallingConventions.Standard, mi.ReturnType, parmTypes);

    //方法体

    {

    var il = methodBuilder.GetILGenerator();

    il.Emit(OpCodes.Ldarg_0);

    il.Emit(OpCodes.Ldfld, fieldBuilder);

    il.Emit(OpCodes.Callvirt, miInvoke);

    if (parmTypes.Length > 0)

    {

    for (int i = 1; i <= parmTypes.Length; ++i)

    {

    switch (i)

    {

    case 0:

    il.Emit(OpCodes.Ldarg_0);

    break;

    case 1:

    il.Emit(OpCodes.Ldarg_1);

    break;

    case 2:

    il.Emit(OpCodes.Ldarg_2);

    break;

    case 3:

    il.Emit(OpCodes.Ldarg_3);

    break;

    default:

    il.Emit(OpCodes.Ldarg_S, i);

    break;

    }

    if (!igoreCrossDomainAttribute)

    {

    //检查参数,如果是 CrossDomain ,并且是Action 或者是 Func<T> 进行跨域替换

    Type prmType = parmTypes[i - 1];

    var prmInfo = parmInfos[i - 1];

    if (prmInfo.GetCustomAttributes(typeof(CallerDomainRun), true).Length > 0)

    {

    if (prmType.Equals(typeof(Action)))

    {

    il.Emit(OpCodes.Call, miActionConverter);

    }

    else if (prmType.IsGenericType && (prmType.BaseType == typeof(Func<>).BaseType))

    {

    var miProxy = miFuncConverter.GetOrAdd(prmType, rt =>

    {

    var typeProxy = typeof(RemoteFuncProxy<>).MakeGenericType(rt.GetGenericArguments());

    return typeProxy.GetMethod("CreateProxyFunc");

    });

    il.Emit(OpCodes.Call, miProxy);

    }

    }

    }

    }

    }

    il.Emit(OpCodes.Callvirt, mi);

    if (mi.ReturnType == typeof(void))

    {

    il.Emit(OpCodes.Pop);

    }

    il.Emit(OpCodes.Ret);

    }

    map.Add(mi, methodBuilder);

    });

    。。。

    }

  • 相关阅读:
    Algs4-2.1.23纸牌排序
    python字符串加颜色区别
    python学习之字典
    python学习之while语句
    python学习之字符串变量
    python学习之列表语法
    python简单实现用户表单登录
    python学习之安装模块
    python学习之认识字符串
    python学习之for语句
  • 原文地址:https://www.cnblogs.com/evlon/p/CallerDomainRun.html
Copyright © 2020-2023  润新知