基于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);

 

});

。。。

}

 

 

posted @ 2012-10-14 21:29  阿牛  阅读(811)  评论(4编辑  收藏  举报