编辑(TLDR),我的问题是: 为什么这两种方法之间存在巨大差距(10倍) 。
有(我认为)两种动态创建类型的方法:使用Emit,以及运行时的源代码。我想对这两者进行基准测试,我发现从源代码编译的速度要快10倍。这是正常的吗?我觉得我做错了什么。
这里我定义了我创建的类型数量(4000)。
static int limit = 4000;
这是允许我使用CSharpCodeProvider
创建4000种类型的代码 [TestMethod]
public void TEST_WITH_COMPILATION()
{
System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
watch.Start();
StringBuilder builder = new StringBuilder();
builder.Append("using System;\n");
builder.Append("namespace MyDynamicAssembly\n");
builder.Append("{\n");
for (int i = 0; i < limit; i++)
{
builder.Append(@"
public class MyType"+i+ @"
{
public int ID { get; set; }
public string Name { get; set; }
}");
}
builder.Append("\n}");
CompilerResults results = new CSharpCodeProvider().CompileAssemblyFromSource(new CompilerParameters
{
GenerateInMemory = true,
GenerateExecutable = false,
}, builder.ToString());
var types = results.CompiledAssembly.GetTypes();
System.Diagnostics.Debug.WriteLine(watch.Elapsed, " Compiled");
}
这是允许我使用Emit
创建4000种类型的代码 [TestMethod]
public void TEST_WITH_EMIT()
{
System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
watch.Start();
ModuleBuilder moduleBuilder = AppDomain
.CurrentDomain
.DefineDynamicAssembly(new AssemblyName("MyDynamicAssembly"), AssemblyBuilderAccess.Run)
.DefineDynamicModule("MyModule");
List<Type> types = new List<Type>();
for (int i=0; i < limit; i++)
{
TypeBuilder typeBuilder = moduleBuilder.DefineType("MyType" + i, TypeAttributes.Public);
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
CreateAutoImplementedProperty(typeBuilder, "ID", typeof(int));
CreateAutoImplementedProperty(typeBuilder, "Name", typeof(string));
types.Add(typeBuilder.CreateType());
}
System.Diagnostics.Debug.WriteLine(watch.Elapsed, " Emitted");
}
CreateAutoImplementedProperty的源代码:
public static void CreateAutoImplementedProperty(TypeBuilder builder, string propertyName, Type propertyType)
{
const string PrivateFieldPrefix = "m_";
const string GetterPrefix = "get_";
const string SetterPrefix = "set_";
FieldBuilder fieldBuilder = builder.DefineField(
string.Concat(PrivateFieldPrefix, propertyName),
propertyType, FieldAttributes.Private);
PropertyBuilder propertyBuilder = builder.DefineProperty(
propertyName, PropertyAttributes.HasDefault, propertyType, null);
MethodAttributes propertyMethodAttributes =
MethodAttributes.Public | MethodAttributes.SpecialName |
MethodAttributes.HideBySig;
MethodBuilder getterMethod = builder.DefineMethod(
string.Concat(GetterPrefix, propertyName),
propertyMethodAttributes, propertyType, Type.EmptyTypes);
ILGenerator getterILCode = getterMethod.GetILGenerator();
getterILCode.Emit(OpCodes.Ldarg_0);
getterILCode.Emit(OpCodes.Ldfld, fieldBuilder);
getterILCode.Emit(OpCodes.Ret);
MethodBuilder setterMethod = builder.DefineMethod(
string.Concat(SetterPrefix, propertyName),
propertyMethodAttributes, null, new Type[] { propertyType });
ILGenerator setterILCode = setterMethod.GetILGenerator();
setterILCode.Emit(OpCodes.Ldarg_0);
setterILCode.Emit(OpCodes.Ldarg_1);
setterILCode.Emit(OpCodes.Stfld, fieldBuilder);
setterILCode.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getterMethod);
propertyBuilder.SetSetMethod(setterMethod);
}
结果如下:
如何解释性能差距?