我将会问一个可能听起来很奇怪的问题。
有没有一种方法可以在运行时构建一个新的类?或者至少,向现有类添加一个新属性。
我的意思是创建一个不存在的类,而不是现有类的实例。稍后我可以使用反射来加载和使用这个类。
我将会问一个可能听起来很奇怪的问题。
有没有一种方法可以在运行时构建一个新的类?或者至少,向现有类添加一个新属性。
我的意思是创建一个不存在的类,而不是现有类的实例。稍后我可以使用反射来加载和使用这个类。
无法向现有类型添加属性,但您可以使用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();
}