首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Reflection.Emit的性能惩罚

Reflection.Emit的性能惩罚
EN

Stack Overflow用户
提问于 2012-01-11 22:38:48
回答 2查看 1.6K关注 0票数 2

我正在考虑一个可能的解决方案来解决我正在研究的一个问题(.NET 3.5 WinForms应用程序)。

在我们的应用程序中,我们有许多方法(C#),其参数由应用程序的用户输入。

例如:

代码语言:javascript
复制
public void DoSomething(string name, DateTime date)
{
   // ...
}

当前使用一个简单的文本框输入名称、日期。我们希望有丰富的编辑器,密码保护输入框,自动完成,等等的好处。

我希望用户的输入使用PropertyGrid,但是该控件只能绑定到对象,而不能绑定参数。

我读过MSDN杂志关于ProperyGrid的两篇优秀文章:

ICustomTypeDescriptor,第一部分

ICustomTypeDescriptor,第2部分

但是,在预先知道将绑定到PropertyGrid的对象的情况下,这似乎是有帮助的,这不是我的情况。

这个场景能支持吗?有什么简单容易实现的解决方案吗?

我考虑使用Reflection.Emit在运行时创建一个"temp“对象,其属性将是该方法的参数。我以前从未这样做过(使用Reflection.Emit命名空间),我想知道使用它的性能损失吗?(它实际上是在内存中运行时编译代码,还是如何工作?)

EN

回答 2

Stack Overflow用户

发布于 2012-01-11 23:56:03

是的,使用Reflection.Emit可以做到这一点(使用与方法参数相对应的属性创建代理类型)。有了这个之后,就可以将代理对象的一个实例分配给PropertyGrid,然后使用输入的值来调用该方法。然而,你想做的事情并不是微不足道的。

我将向您介绍TypeBuilder的MSDN文档,以获得使用Reflection.Emit创建类型的示例。

为了回答有关性能的问题,是的,代码是“在内存中”编译的。您通常想要做的是在字典中缓存生成的类型,以便可以重用它。最大的性能打击是在类型生成。创建该类型的实例可能非常便宜(取决于您是如何创建的-- Activator.CreateInstance()是最慢的,如下所示:

代码语言:javascript
复制
private Func<T> GetCreator()
    {
        if (_Creator == null)
        {
            Expression body;
            var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
            var defaultConstructor = typeof(T).GetConstructor(bindingFlags, null, new Type[0], null);
            if (defaultConstructor != null)
            {
                // lambdaExpression = () => (object) new TClass()
                body = Expression.New(defaultConstructor);
            }
            else
            {
                // lambdaExpression = () => FormatterServices.GetUninitializedObject(classType)
                var getUnitializedObjectMethodInfo = typeof(FormatterServices).GetMethod("GetUninitializedObject", BindingFlags.Public | BindingFlags.Static);
                body = Expression.Call(getUnitializedObjectMethodInfo, Expression.Constant(typeof(T)));
            }
            var lambdaExpression = Expression.Lambda<Func<T>>(body);
            _Creator = lambdaExpression.Compile();
        }
        return _Creator;
    }

,它允许您只需调用

代码语言:javascript
复制
object obj = GetCreator()();

使用这种模式,当应用程序刚刚开始时,您将看到性能下降,但是随着缓存丢失的减少,它的性能将几乎与内联代码一样好。

您可以使用类似的方法生成调用者--这里有一个很好的示例:

http://www.codeproject.com/KB/cs/FastMethodInvoker.aspx

票数 3
EN

Stack Overflow用户

发布于 2012-01-11 23:24:08

这里有多少相同的问题,它的解决办法。它是为.NET 3.5编写的,运行良好。目标是将所有web方法集中在单个web服务(.asmx)中,并从单个位置调用任何已注册的方法。代码可能要小得多。但是,由于一些强制转换,它有点长。

代码语言:javascript
复制
public object ExecuteMethod(string moduleName, string methodName, object[] arguments)
{
  CmsModuleMethodInfo methodInfo = CmsModuleManager.GetModuleMethod(moduleName, methodName);
  ...

  ParameterInfo[] paramInfo = methodInfo.Method.GetParameters();
  Object[] parameters = new Object[paramInfo.Length];
  Type[] paramTypes = paramInfo.Select(x => x.ParameterType).ToArray();
  for (int i = 0; i < parameters.Length; ++i)
  {
    Type paramType = paramTypes[i];
    Type passedType = (arguments[i] != null) ? arguments[i].GetType() : null;

    if (paramType.IsArray)
    {
      // Workaround for InvokeMethod which is very strict about arguments.
      // For example, "int[]" is casted as System.Object[] and
      // InvokeMethod raises an exception in this case.
      // So, convert any object which is an Array actually to a real Array.
      int n = ((Array)arguments[i]).Length;
      parameters[i] = Array.CreateInstance(paramType.GetElementType(), n);
      Array.Copy((Array)arguments[i], (Array)parameters[i], n);
    }
    else if ((passedType == typeof(System.Int32)) && (paramType.IsEnum))
    {
      parameters[i] = Enum.ToObject(paramType, (System.Int32)arguments[i]);
    }
    else
    {
      // just pass it as it's
      parameters[i] = Convert.ChangeType(arguments[i], paramType);
    }
  }

  object result = null;
  try
  {
    result = methodInfo.Method.Invoke(null, parameters);
  }
  catch (TargetInvocationException e)
  {
    if (e.InnerException != null)
    {
      throw e.InnerException;
    }
  }

  return result;
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8827771

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档