为什么C#使用dynamic调用外部程序集方法会在运行时抛出异常?
问题根因
你遇到的异常本质是C# dynamic的运行时绑定逻辑依旧遵守访问权限控制规则,不会绕过类型可见性限制:
- 你外部dll中定义的
ProxyFactory是internal修饰的,仅在a.b.c程序集内部可见,你的业务代码所在的程序集没有访问该类型成员的权限 - 动态绑定时,因为调用方无法识别
ProxyFactory类型,会将其当做object类型处理,自然找不到Get方法 - 调试时反射能看到
Get方法是因为反射默认不校验访问修饰符限制,和dynamic的绑定逻辑不同
解决方案
不需要强制用反射Invoke的方式实现需求,可根据实际情况选择以下成本更低的方案:
- 方案1(优先推荐,仅需修改外部dll少量代码):将
FactoryCreator.CreateFactory的返回值类型从internal的ProxyFactory改为public的FactoryIfc接口:
namespace Ext { public static class FactoryCreator { // 仅修改返回值类型为公开接口 public static FactoryIfc CreateFactory() { return new ProxyFactory(); } } }
因为FactoryIfc是公开类型,dynamic绑定时可以正常识别到接口定义的Get方法,业务代码无需改动即可正常运行。
- 方案2(无需修改外部dll,性能最优):如果你的业务项目已经引用了外部dll的公开元数据,直接将返回实例转换为
FactoryIfc接口调用即可,不需要用dynamic:
var assembly = "a.b.c, Version=1.0.0.0, Culture=neutral, PublicKeyToken=<key>,processorArchitecture=MSIL"; var instName = "Ext.FactoryCreator"; Ext.FactoryIfc factory = (Ext.FactoryIfc)AppDomain.CurrentDomain.Load(assembly) .GetType(instName) .GetMethod("CreateFactory") .Invoke(null, new object[0]); var proxy = factory.Get();
- 方案3(无法修改外部dll代码时可选):给外部dll添加
InternalsVisibleTo特性,授权你的业务程序集访问它的内部成员:
在外部dll的AssemblyInfo.cs文件中添加如下代码:
[assembly: InternalsVisibleTo("你的业务程序集名称, PublicKey=<业务程序集强签名公钥(非强签名可省略>")]
配置后dynamic即可正常识别ProxyFactory的内部成员。
内容的提问来源于stack exchange,提问作者NirMH
相关产品推荐
相关产品推荐

