【发布时间】:2009-05-30 08:35:27
【问题描述】:
我要问一个听起来很奇怪的问题。
有没有办法在运行时构建一个新类?或者至少,向现有类添加一个新属性。
我的意思是创建一个不存在的类,而不是现有类的实例。我以后可以使用反射来加载和使用这个类。
【问题讨论】:
标签: c# .net vb.net reflection
我要问一个听起来很奇怪的问题。
有没有办法在运行时构建一个新类?或者至少,向现有类添加一个新属性。
我的意思是创建一个不存在的类,而不是现有类的实例。我以后可以使用反射来加载和使用这个类。
【问题讨论】:
标签: c# .net vb.net reflection
无法向现有类型添加属性,但您可以在运行时使用 Reflection.Emit 创建新类型。这是相当复杂的东西,它是这样的:
AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(
assemblyName , AssemblyBuilderAccess.Run, assemblyAttributes);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("ModuleName");
TypeBuilder typeBuilder = moduleBuilder.DefineType(
"MyNamespace.TypeName" , TypeAttributes.Public);
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
// Add a method
newMethod = typeBuilder.DefineMethod("MethodName" , MethodAttributes.Public);
ILGenerator ilGen = newMethod.GetILGenerator();
// Create IL code for the method
ilGen.Emit(...);
// ...
// Create the type itself
Type newType = typeBuilder.CreateType();
此代码只是一个示例。它可能包含错误。
你也可以通过在运行时使用 System.CodeDom 编译 C# 源代码来生成类,但我对此了解不多。
【讨论】:
查看System.Reflection.Emit 命名空间。我自己从来没有使用过,但是这个命名空间中的类可以用来生成 IL(中间语言)。
【讨论】:
这不是一个奇怪的问题 - 在某些情况下它可能非常有用。例如,我有时会使用这种技术进行性能测试:
public static Type[] DynamicTypes;
public void CreateObjects()
{
var codeNamespace = new CodeNamespace( "DynamicClasses" );
codeNamespace.Imports.Add( new CodeNamespaceImport( "System" ) );
codeNamespace.Imports.Add( new CodeNamespaceImport( "System.ComponentModel" ) );
for( var i = 0; i < 2000; i++ )
{
var classToCreate = new CodeTypeDeclaration( "DynamicClass_" + i )
{
TypeAttributes = TypeAttributes.Public
};
var codeConstructor1 = new CodeConstructor
{
Attributes = MemberAttributes.Public
};
classToCreate.Members.Add( codeConstructor1 );
codeNamespace.Types.Add( classToCreate );
}
var codeCompileUnit = new CodeCompileUnit();
codeCompileUnit.Namespaces.Add( codeNamespace );
var compilerParameters = new CompilerParameters
{
GenerateInMemory = true,
IncludeDebugInformation = true,
TreatWarningsAsErrors = true,
WarningLevel = 4
};
compilerParameters.ReferencedAssemblies.Add( "System.dll" );
var compilerResults = new CSharpCodeProvider().CompileAssemblyFromDom( compilerParameters, codeCompileUnit );
if( compilerResults == null )
{
throw new InvalidOperationException( "ClassCompiler did not return results." );
}
if( compilerResults.Errors.HasErrors )
{
var errors = string.Empty;
foreach( CompilerError compilerError in compilerResults.Errors )
{
errors += compilerError.ErrorText + "\n";
}
Debug.Fail( errors );
throw new InvalidOperationException( "Errors while compiling the dynamic classes:\n" + errors );
}
var dynamicAssembly = compilerResults.CompiledAssembly;
DynamicTypes = dynamicAssembly.GetExportedTypes();
}
【讨论】:
您可以查看System.CodeDom 命名空间。根据从那里链接的页面之一:
.NET Framework 包含一种称为代码文档对象模型 (CodeDOM) 的机制,它使发出源代码的程序的开发人员能够在运行时生成多种编程语言的源代码,该模型基于表示代码的单一模型渲染。
我根本不是这方面的专家,我只记得在我墙上的 .NET Framework 海报上看到过它。 :)
编辑:自从写下这个答案后,我就玩过 System.CodeDom 了。我写了一个blog post,它使用了一些基本的 CodeDom,可以帮助那些想要开始使用它的人。
【讨论】: