动态演员与反射调用:选择哪种毒药?

时间:2016-02-26 03:36:20

标签: c# dynamic reflection casting

我正面临一个小困境。

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

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是一个主要的性能瓶颈,因此我决定在调用之前反思有问题的类型,然后再发现该方法是否存在。

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

我的提交信息如下:

  

通过反映上下文类型来找到要使用的方法,从而消除了RuntimeBinderException的可能性。 保持(动态)强制转换因为被认为比反映调用更便宜 ..但可能是错误的。

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

2 个答案:

答案 0 :(得分:1)

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

RelativeLayout

使用不同的 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

答案 1 :(得分:0)

不确定这是否适合你......

using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;

public class Purchase : MonoBehaviour,IPointerClickHandler
{
    public GameObject purchasePanel;
    public GameObject panelPosition;

public void OnPointerClick (PointerEventData eventData)
    {

        GameObject instantiatedPurchase = Instantiate(purchasePanel, panelPosition.transform.position,panelPosition.transform.rotation) as GameObject;  
    instantiatedPurchase.transform.SetParent(panelPosition.transform);
}