C# 优化动态类型上的方法调用

C# 优化动态类型上的方法调用,c#,performance,com,dynamic-language-runtime,C#,Performance,Com,Dynamic Language Runtime,下面的代码实例化了一个已注册的COM对象 private dynamic server = null // Global variable. ... Type type = Type.GetTypeFromProgID("Svr.GrpCall"); this.server = Activator.CreateInstance(type); 我可以使用非常直观的符号从这个COM/动态对象调用方法 string expectedResult = this.server.GroupInit(som

下面的代码实例化了一个已注册的COM对象

private dynamic server = null // Global variable.
...
Type type = Type.GetTypeFromProgID("Svr.GrpCall");
this.server = Activator.CreateInstance(type);
我可以使用非常直观的符号从这个COM/
动态对象调用方法

string expectedResult = this.server.GroupInit(someString, someBoolean);
对于单次调用,通过动态语言运行库(DLR)调用此类方法的性能是可移植的。但是,对于一个需求,我需要对数千条记录使用双
for
循环,该循环在COM对象中使用返回
void

for (int i = 0; i < MAXREC; i++)
    for (int j = 0; j < MAXFIELDS; j++)
        this.server.MakeRecord(s1, s2, str);
其中计划在上面的for循环中使用这个。在使用此
操作之前,我尝试先初始化服务器(如上所述),然后使用

Type type = Type.GetTypeFromProgID("Svr.GrpCall");
this.server = Activator.CreateInstance(type);

MethodInfo methodInfo = type.GetMethod("MakeRecord");
makeRecord = (Action<short, short, string>)Delegate.CreateDelegate(type, methodInfo);

您如何知道缓慢的行为是由于使用了
动态

  • 您是否尝试过为COM接口使用强类型托管包装器并直接调用它们(即不使用
    动态
    和不使用任何反射方法)?您可以添加对COM程序集本身的引用,以自动创建托管包装器
  • 您是否尝试过在调试器之外运行代码?在调试器中运行代码会导致对本机代码的方法调用(包括COM接口调用)的性能达到100:1
  • 您是否考虑过更新接口以提供所需算法的更直接的实现,从而可以在托管代码中进行更少的函数调用

非常感谢您的回复。我已经分析了代码,可以看出对COM对象的
动态调用是缓慢的。人们认识到,这些调用可能非常慢,因为DLR必须在每次调用时使用它(如所述)。关于第一点,您是指使用“Tlbimp.exe”创建C#包装器吗?我已经在发布模式下运行了代码&结果是一样的。COM库,因为它是第三方和传统的。也没有办法优化我对调用的使用,因为它是数据情况的一个剪切权重……在探查器中,您如何区分
动态
的开销和方法本身的成本?如果
MakeRecord
本身就是一个缓慢的方法,那么无论您是否使用
dynamic
,都没有关系,因为这不是瓶颈。是的,我知道这一点。我之所以知道这种方法“不慢”,是因为遗留COM库附带了一个旧的示例VB6应用程序。此应用程序可以“直接”调用COM方法,这可以在5秒内调用
MakeRecord
6000次。当我在C#中执行完全相同的操作时,使用
dynamic
这一次(对于完全相同的数据集)增加到大约1分钟。再次感谢您的时间…山姆,在回复您的评论之前,我已经离开了一段时间,因为我一直在看您的个人资料->ANTLR->Terence Parr的演讲->买书等等。!我对这项工作感到惊讶。我最近写了一个通用语法高亮(没有什么比ANTLR),最近被要求重写旧的C++编译器/静态分析器,用于保险行业中使用的一些伪代码,也加入了不同的语言格式……最初我被吞了,认为这将是艰难的(但有趣)-然后我找到了ANTLR!在我发起全面攻击之前,可以通过电子邮件向您提出一些关于ANTLR的简短问题吗?
Type type = Type.GetTypeFromProgID("Svr.GrpCall");
this.server = Activator.CreateInstance(type);

MethodInfo methodInfo = type.GetMethod("MakeRecord");
makeRecord = (Action<short, short, string>)Delegate.CreateDelegate(type, methodInfo);
object o = Activator.CreateInstance(type);
MethodInfo methodInfo = o.GetType().GetMethod("MakeRec");