c# - 创建运行时确定类型实例的最佳方法

标签 c# performance dynamic reflection runtime

<分区>

(在 .NET 4 中)创建在运行时确定的类型的实例的最佳方法是什么。

我有一个实例方法,尽管它作用于 BaseClass 对象,但它的派生类的实例可能会调用它。我需要在方法中创建另一个与 this 类型相同的实例。为每个派生类重载方法是不切实际的,因为它相当复杂,并且保持单一实现会更有效。

public class BaseClass
{
     //constructors + properties + methods etc

     public SomeMethod()
     {
          //some code

          DerivedClass d = new DerivedClass(); //ideally determine the DerivedClass type at run-time
     }
}

我读过一些关于反射或使用动态关键字的内容,但我没有这方面的经验。

最佳答案

在运行时重复创建实例的最佳性能方式是编译表达式:

static readonly Func<X> YCreator = Expression.Lambda<Func<X>>(
   Expression.New(typeof(Y).GetConstructor(Type.EmptyTypes))
 ).Compile();

X x = YCreator();

统计数据(2012 年):

    Iterations: 5000000
    00:00:00.8481762, Activator.CreateInstance(string, string)
    00:00:00.8416930, Activator.CreateInstance(type)
    00:00:06.6236752, ConstructorInfo.Invoke
    00:00:00.1776255, Compiled expression
    00:00:00.0462197, new

统计数据(2015 年,.net 4.5,x64):

    Iterations: 5000000
    00:00:00.2659981, Activator.CreateInstance(string, string)
    00:00:00.2603770, Activator.CreateInstance(type)
    00:00:00.7478936, ConstructorInfo.Invoke
    00:00:00.0700757, Compiled expression
    00:00:00.0286710, new

统计数据(2015 年,.net 4.5,x86):

    Iterations: 5000000
    00:00:00.3541501, Activator.CreateInstance(string, string)
    00:00:00.3686861, Activator.CreateInstance(type)
    00:00:00.9492354, ConstructorInfo.Invoke
    00:00:00.0719072, Compiled expression
    00:00:00.0229387, new

完整代码:

public static X CreateY_New()
{
  return new Y();
}

public static X CreateY_CreateInstance()
{
  return (X)Activator.CreateInstance(typeof(Y));
}

public static X CreateY_CreateInstance_String()
{
  return (X)Activator.CreateInstance("Program", "Y").Unwrap();
}

static readonly System.Reflection.ConstructorInfo YConstructor = 
    typeof(Y).GetConstructor(Type.EmptyTypes);
static readonly object[] Empty = new object[] { };
public static X CreateY_Invoke()
{
  return (X)YConstructor.Invoke(Empty);
}

static readonly Func<X> YCreator = Expression.Lambda<Func<X>>(
   Expression.New(typeof(Y).GetConstructor(Type.EmptyTypes))
 ).Compile();
public static X CreateY_CompiledExpression()
{
  return YCreator();
}

static void Main(string[] args)
{
  const int iterations = 5000000;

  Console.WriteLine("Iterations: {0}", iterations);

  foreach (var creatorInfo in new [] 
    { 
      new {Name = "Activator.CreateInstance(string, string)", Creator = (Func<X>)CreateY_CreateInstance},
      new {Name = "Activator.CreateInstance(type)", Creator = (Func<X>)CreateY_CreateInstance},
      new {Name = "ConstructorInfo.Invoke", Creator = (Func<X>)CreateY_Invoke},
      new {Name = "Compiled expression", Creator = (Func<X>)CreateY_CompiledExpression},
      new {Name = "new", Creator = (Func<X>)CreateY_New},
    })
  {
    var creator = creatorInfo.Creator;

    var sum = 0;
    for (var i = 0; i < 1000; i++)
      sum += creator().Z;

    var stopwatch = new Stopwatch();
    stopwatch.Start();
    for (var i = 0; i < iterations; ++i)
    {
      var x = creator();
      sum += x.Z;
    }
    stopwatch.Stop();
    Console.WriteLine("{0}, {1}", stopwatch.Elapsed, creatorInfo.Name);
  }
}

public class X
{
  public X() { }
  public X(int z) { this.Z = z; }
  public int Z;
}
public class Y : X { }

关于c# - 创建运行时确定类型实例的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9788813/

相关文章:

ios - 建筑的 undefined symbol ..在动态框架中

javascript - 检测使用 javascript 动态分配的 css 样式/属性

c# - 在构造函数期间关闭表单

c# - 通过 DotNetZip 库以编程方式提取 ZIP 文件?

c# - GridView 中的数据未正确显示

c - 双核 ARMv7 处理器中的并行处理

java - 如何停止在 CollapsingToolbarLayout 上滚动,使其不会完全折叠

c# - 分数 API - 更新请求返回 HTTP 403 错误,(#200) 用户无法访问此应用程序

performance - mod_pagespeed 是做什么的?

javascript - Angular - 自动更新数据而不刷新页面