有没有办法在运行时构建新类型?

我会问一个可能听起来很奇怪的问题。

有没有办法在运行时构建一个新类? 或者至少,向现有类添加新属性。

我的意思是创建一个不存在的类,而不是现有类的实例。 我以后可以使用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#源代码来生成类,但我对此并不了解。

这不是一个奇怪的问题 – 在某些情况下它可能非常有用。 例如,我有时会使用这种技术进行性能测试:

 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.Reflection.Emit命名空间。 我自己从未使用它,但此命名空间中的类可用于生成IL(中间语言)。

您可以查看System.CodeDom命名空间。 根据其中一个页面链接:

.NET Framework包含一种称为代码文档对象模型(CodeDOM)的机制,它使得发出源代码的程序的开发人员能够在运行时基于表示要呈现的代码的单个模型在运行时生成多种编程语言的源代码。

我不是这方面的专家,我只记得在我墙上的.NET Framework海报上看到它。 🙂

编辑:自写这个答案以来,我已经使用了System.CodeDom了。 我写了一篇博文 ,其中使用了一些基本的CodeDom,可以帮助那些想要开始使用它的人。