Asb*_*erg 3 c# generics reflection delegates
我正在创建一个框架,其中包含一个围绕库(特别是SharpBrake)的包装器,它通过反射执行与SharpBrake的所有交互,因此对我的框架的第三方没有硬件依赖库.
如果我的框架的第三方想要使用SharpBrake,他们可以将SharpBrake.dll填充到bin文件夹中,但如果他们不这样做,他们就可以忘掉它.如果我的框架明确引用了SharpBrake类型,那么我的框架用户会在SharpBrake.dll缺失的运行时期间遇到异常,这是我不想要的.
因此,我的包装器首先从磁盘加载SharpBrake.dll,找到AirbrakeClient类型,并AirbrakeClient.Send(AirbrakeNotice)在私有字段中存储指向该方法的委托.然而,我的问题是,由于该Send()方法需要一个AirbrakeNotice对象而我无法AirbrakeNotice直接引用该对象,我需要以某种方式将该Send()方法转换为Action<object>.
我有一种强烈的感觉,这是不可能的,但我想在解决暴露Delegate和使用之前探索所有选项DynamicInvoke(),我认为这远非最佳,性能方面.我想做的是以下内容:
Type clientType = exportedTypes.FirstOrDefault(type => type.Name == "AirbrakeClient");
Type noticeType = exportedTypes.FirstOrDefault(type => type.Name == "AirbrakeNotice");
MethodInfo sendMethod = clientType.GetMethod("Send", new[] { noticeType });
object client = Activator.CreateInstance(clientType);
Type actionType = Expression.GetActionType(noticeType);
Delegate sendMethodDelegate = Delegate.CreateDelegate(actionType, client, sendMethod);
// This fails with an InvalidCastException:
Action<object> sendAction = (Action<object>)sendMethodDelegate;
Run Code Online (Sandbox Code Playgroud)
但是,此操作失败,并出现以下异常:
System.InvalidCastException:无法将类型为'System.Action`1 [SharpBrake.Serialization.AirbrakeNotice]'的对象强制转换为'System.Action`1 [System.Object]'.
显然,因为sendMethodDelegate是一个Action<AirbrakeNotice>而不是一个Action<object>.由于我AirbrakeNotice在代码中无法提及,我不得不这样做:
Action<object> sendAction = x => sendMethodDelegate.DynamicInvoke(x);
Run Code Online (Sandbox Code Playgroud)
或直接暴露Delegate sendMethodDelegate.这可能吗?我知道有机会进入object可能与不同类型不同的情况AirbrakeNotice,但无论如何看到你有多少可以搞乱反思,我希望在某个地方有一个漏洞.
如果你很乐意使用表达式树,那就相当简单了:
ConstantExpression target = Expression.Constant(client, clientType);
ParameterExpression parameter = Expression.Parameter(typeof(object), "x");
Expression converted = Expression.Convert(parameter, noticeType);
Expression call = Expression.Call(target, sendMethod, converted);
Action<object> action = Expression.Lambda<Action<object>>(call, parameter)
.Compile();
Run Code Online (Sandbox Code Playgroud)
我想这就是你想要的......