C# 动态施法与反射调用:选择哪种毒药?

C# 动态施法与反射调用:选择哪种毒药?,c#,dynamic,reflection,casting,C#,Dynamic,Reflection,Casting,我面临着一个小小的困境 我需要在类型的许多实例上重复调用给定的方法,这些实例可能存在,也可能不存在。由于该方法的结果对于任何给定实例都不会改变,因此我正在缓存其返回值以备将来使用,以减少开销并在后续调用时尽早返回,但实际执行工作的部分仍然需要调用可能不存在的该方法: 捕获/处理一个RuntimeBinderException是一个主要的性能瓶颈,因此我决定在调用该方法之前,仔细考虑所讨论的类型,并发现该方法是否存在 Context.Parent的特定类型在编译时是未知的,可能的运行时类型不共享一

我面临着一个小小的困境

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

捕获/处理一个
RuntimeBinderException
是一个主要的性能瓶颈,因此我决定在调用该方法之前,仔细考虑所讨论的类型,并发现该方法是否存在

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

我的提交消息如下所示:

通过反射上下文类型来定位要使用的方法,消除了RuntimeBinderException的可能性保留(动态)强制转换,因为被认为比反射调用便宜。。但这可能是错误的


哪一个开销最小,更重要的是,为什么?

不确定这是否适用于您

public async Task<tokenclass> Process(Button Context){
            var x = await Task.Run(() =>
            {
                tokenclass tc = new tokenclass();
                var method = Context.Parent.GetType().GetMethod("typeHint");
                if (method == null)
                {
                    tc.token = null;
                    tc.hasTypeHing = false;
                    tc.result = false;                   
                }
                return tc;
            });
            return x;


   public class tokenclass
    {
        public string token { get; set; }
        public bool hasTypeHing { get; set; }
        public bool result { get; set; }
    }
公共异步任务进程(按钮上下文){
var x=等待任务。运行(()=>
{
tokenclass tc=新的tokenclass();
var method=Context.Parent.GetType().GetMethod(“typeHint”);
if(方法==null)
{
tc.token=null;
tc.hasTypeHing=false;
tc.result=false;
}
返回tc;
});
返回x;
公共类令牌类
{
公共字符串标记{get;set;}
公共bool hasTypeHing{get;set;}
公共布尔结果{get;set;}
}

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

        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();
var sw=新秒表();
int loopLimit=10000000;
对象hint1;
sw.Start();
对于(变量i=0;i
使用不同的
loopLimit
值,您将看到,对于相对较少的调用数,
Invoke
更快。当您增加
loopLimit
时,动态调用会赶上,然后速度会快得多。为什么?因为动态调用会缓存执行该操作所需的表达式树。在这种情况下re是唯一一个创建的表达式树,因为我没有更改对象(在调用站点,每个对象类型只有一个表达式树)

因此,长话短说,如果您只调用了几千次,或者您有大量的对象类型要测试和调用,那么表达式树的创建将破坏您的性能,
Invoke
将更好。如果对象可以是少数类型之一,并且您的方法被调用了数百万次,那么您可能会更好地带有
动态调用的ff


根据您的具体情况使用数字。我猜您会选择
Invoke

为什么开销是您关心的问题?您是否在一个紧密的循环中多次调用此方法?@dasblinkenlight我正在迭代(至少)数百个实例(取决于数据)这种类型的,所以是的。分析真的就像大海捞针。当我面对这些类型的问题时,我立即开始考虑异步技术。我知道使用反射是昂贵的,但如果你需要多少线程,可能就没有那么多了,对吧?我不明白动态的e是有效的,必须更深入地研究它。@JohnPeters是对的。我忘了提到,所讨论的方法是从异步任务中调用的。不过,我正试图降低CPU使用率,而该代码是我的目标之一。还有其他类似的方法,所以无论哪种方法更好,都会应用到其他地方。不会产生新的问题任务内的任务(已从异步任务调用代码)招致更多的开销?我已经编辑了OP以包含
标记
位,如果它让人困惑的话,很抱歉。它可以,但你可以测试它以确保。我有一台笔记本电脑,有7个CPU和大量内存,所以我在某种程度上与你提到的问题无关。太棒了,我不知道涉及表达式树!因此如果我理解正确,我是真的最好使用反射来完成这个。谢谢!
        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();