gpt4 book ai didi

c# - 动态转换与反射调用 : which poison to pick?

转载 作者:行者123 更新时间:2023-11-30 17:39:19 25 4
gpt4 key购买 nike

我面临着一个小难题。

我需要在一个类型的许多实例上重复调用给定的方法,这些实例可能存在也可能不存在。因为对于任何给定实例,该方法的结果永远不会改变,所以我缓存它的返回值以供将来使用,以减少开销并在后续调用中尽早返回,但实际执行工作的部分仍然需要调用该 可能不存在的方法:

var method = Context.Parent.GetType().GetMethod("typeHint");
if (method == null)
{
token = null;
_hasTypeHint = false;
return false;
}

var hint = ((dynamic)Context.Parent).typeHint() as VBAParser.TypeHintContext;
token = hint == null ? null : hint.GetText();
return hint != null;

捕获/处理 RuntimeBinderException 是一个主要的性能瓶颈,所以我决定反射(reflection)有问题的类型,并在调用它之前发现该方法是否存在。

Context.Parent 的特定类型在编译时是未知的,并且可能的运行时类型不共享具有 typeHint() 的公共(public)接口(interface)我正在寻找的方法:我需要调用反射成员,或者转换为 dynamic 并直接调用它。

我的提交信息是这样的:

removed the possibility for RuntimeBinderException by reflecting on the context type to locate the method to use. Kept (dynamic) cast because deemed less expensive than reflection invoke.. could be wrong though.

哪一个产生的开销最少,更重要的是,为什么

最佳答案

好吧,我很好奇,所以我写了一个小程序来测试:

        var sw = new Stopwatch();
int loopLimit = 10000000;
object hint1;
sw.Start();
for( var i = 0; i < loopLimit; i++ )
hint1 = ( ( dynamic )theObject ).ToString();
sw.Stop();
Console.WriteLine( "dynamic time: {0}", sw.ElapsedMilliseconds );
sw.Restart();
for( var i = 0; i < loopLimit; i++ )
hint1 = method.Invoke( theObject, null );
sw.Stop();
Console.WriteLine( "invoke time: {0}", sw.ElapsedMilliseconds );
Console.ReadLine();

尝试使用不同的 loopLimit 值,您会发现对于相对较少的调用,Invoke 速度更快。当您增加 loopLimit 时,动态调用会跟上并变得更快。为什么?因为动态调用缓存了执行操作所需的表达式树。在这种情况下,由于我没有更改 theObject,所以只创建了一个表达式树(在调用站点,每个对象类型将只有一个表达式树)。

所以,长话短说,如果您只调用几千次,或者如果您有大量不同的对象类型要测试和调用,那么表达式树的创建会降低您的性能,Invoke 会更好。如果对象可以是几种类型之一,并且您的方法被调用了数百万次,那么您最好使用 dynamic 调用。

根据您的特定情况使用数字。我猜你会选择 Invoke

关于c# - 动态转换与反射调用 : which poison to pick?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35642965/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com