MetadataBuilder Class
Important
Some information relates to prerelease product that may be substantially modified before it’s released. Microsoft makes no warranties, express or implied, with respect to the information provided here.
The MetadataBuilder class writes metadata for an assembly in a highly performant manner. It is designed for use by compilers and other assembly generation tools.
public ref class MetadataBuilder sealed
public sealed class MetadataBuilder
type MetadataBuilder = class
Public NotInheritable Class MetadataBuilder
- Inheritance
-
MetadataBuilder
This example shows how to emit a console application assembly using MetadataBuilder:
private static readonly Guid s_guid = new Guid("87D4DBE1-1143-4FAD-AAB3-1001F92068E6");
private static readonly BlobContentId s_contentId = new BlobContentId(s_guid, 0x04030201);
private static MethodDefinitionHandle EmitHelloWorld(MetadataBuilder metadata, BlobBuilder ilBuilder)
{
// Create module and assembly for a console application.
metadata.AddModule(
0,
metadata.GetOrAddString("ConsoleApplication.exe"),
metadata.GetOrAddGuid(s_guid),
default(GuidHandle),
default(GuidHandle));
metadata.AddAssembly(
metadata.GetOrAddString("ConsoleApplication"),
version: new Version(1, 0, 0, 0),
culture: default(StringHandle),
publicKey: default(BlobHandle),
flags: 0,
hashAlgorithm: AssemblyHashAlgorithm.None);
// Create references to System.Object and System.Console types.
AssemblyReferenceHandle mscorlibAssemblyRef = metadata.AddAssemblyReference(
name: metadata.GetOrAddString("mscorlib"),
version: new Version(4, 0, 0, 0),
culture: default(StringHandle),
publicKeyOrToken: metadata.GetOrAddBlob(
new byte[] { 0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89 }
),
flags: default(AssemblyFlags),
hashValue: default(BlobHandle));
TypeReferenceHandle systemObjectTypeRef = metadata.AddTypeReference(
mscorlibAssemblyRef,
metadata.GetOrAddString("System"),
metadata.GetOrAddString("Object"));
TypeReferenceHandle systemConsoleTypeRefHandle = metadata.AddTypeReference(
mscorlibAssemblyRef,
metadata.GetOrAddString("System"),
metadata.GetOrAddString("Console"));
// Get reference to Console.WriteLine(string) method.
var consoleWriteLineSignature = new BlobBuilder();
new BlobEncoder(consoleWriteLineSignature).
MethodSignature().
Parameters(1,
returnType => returnType.Void(),
parameters => parameters.AddParameter().Type().String());
MemberReferenceHandle consoleWriteLineMemberRef = metadata.AddMemberReference(
systemConsoleTypeRefHandle,
metadata.GetOrAddString("WriteLine"),
metadata.GetOrAddBlob(consoleWriteLineSignature));
// Get reference to Object's constructor.
var parameterlessCtorSignature = new BlobBuilder();
new BlobEncoder(parameterlessCtorSignature).
MethodSignature(isInstanceMethod: true).
Parameters(0, returnType => returnType.Void(), parameters => { });
BlobHandle parameterlessCtorBlobIndex = metadata.GetOrAddBlob(parameterlessCtorSignature);
MemberReferenceHandle objectCtorMemberRef = metadata.AddMemberReference(
systemObjectTypeRef,
metadata.GetOrAddString(".ctor"),
parameterlessCtorBlobIndex);
// Create signature for "void Main()" method.
var mainSignature = new BlobBuilder();
new BlobEncoder(mainSignature).
MethodSignature().
Parameters(0, returnType => returnType.Void(), parameters => { });
var methodBodyStream = new MethodBodyStreamEncoder(ilBuilder);
var codeBuilder = new BlobBuilder();
InstructionEncoder il;
// Emit IL for Program::.ctor
il = new InstructionEncoder(codeBuilder);
// ldarg.0
il.LoadArgument(0);
// call instance void [mscorlib]System.Object::.ctor()
il.Call(objectCtorMemberRef);
// ret
il.OpCode(ILOpCode.Ret);
int ctorBodyOffset = methodBodyStream.AddMethodBody(il);
codeBuilder.Clear();
// Emit IL for Program::Main
var flowBuilder = new ControlFlowBuilder();
il = new InstructionEncoder(codeBuilder, flowBuilder);
// ldstr "hello"
il.LoadString(metadata.GetOrAddUserString("Hello, world"));
// call void [mscorlib]System.Console::WriteLine(string)
il.Call(consoleWriteLineMemberRef);
// ret
il.OpCode(ILOpCode.Ret);
int mainBodyOffset = methodBodyStream.AddMethodBody(il);
codeBuilder.Clear();
// Create method definition for Program::Main
MethodDefinitionHandle mainMethodDef = metadata.AddMethodDefinition(
MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig,
MethodImplAttributes.IL,
metadata.GetOrAddString("Main"),
metadata.GetOrAddBlob(mainSignature),
mainBodyOffset,
parameterList: default(ParameterHandle));
// Create method definition for Program::.ctor
MethodDefinitionHandle ctorDef = metadata.AddMethodDefinition(
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
MethodImplAttributes.IL,
metadata.GetOrAddString(".ctor"),
parameterlessCtorBlobIndex,
ctorBodyOffset,
parameterList: default(ParameterHandle));
// Create type definition for the special <Module> type that holds global functions
metadata.AddTypeDefinition(
default(TypeAttributes),
default(StringHandle),
metadata.GetOrAddString("<Module>"),
baseType: default(EntityHandle),
fieldList: MetadataTokens.FieldDefinitionHandle(1),
methodList: mainMethodDef);
// Create type definition for ConsoleApplication.Program
metadata.AddTypeDefinition(
TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.AutoLayout | TypeAttributes.BeforeFieldInit,
metadata.GetOrAddString("ConsoleApplication"),
metadata.GetOrAddString("Program"),
baseType: systemObjectTypeRef,
fieldList: MetadataTokens.FieldDefinitionHandle(1),
methodList: mainMethodDef);
return mainMethodDef;
}
private static void WritePEImage(
Stream peStream,
MetadataBuilder metadataBuilder,
BlobBuilder ilBuilder,
MethodDefinitionHandle entryPointHandle
)
{
// Create executable with the managed metadata from the specified MetadataBuilder.
var peHeaderBuilder = new PEHeaderBuilder(
imageCharacteristics: Characteristics.ExecutableImage
);
var peBuilder = new ManagedPEBuilder(
peHeaderBuilder,
new MetadataRootBuilder(metadataBuilder),
ilBuilder,
entryPoint: entryPointHandle,
flags: CorFlags.ILOnly,
deterministicIdProvider: content => s_contentId);
// Write executable into the specified stream.
var peBlob = new BlobBuilder();
BlobContentId contentId = peBuilder.Serialize(peBlob);
peBlob.WriteContentTo(peStream);
}
public static void BuildHelloWorldApp()
{
using var peStream = new FileStream(
"ConsoleApplication.exe", FileMode.OpenOrCreate, FileAccess.ReadWrite
);
var ilBuilder = new BlobBuilder();
var metadataBuilder = new MetadataBuilder();
MethodDefinitionHandle entryPoint = EmitHelloWorld(metadataBuilder, ilBuilder);
WritePEImage(peStream, metadataBuilder, ilBuilder, entryPoint);
}
The MetadataBuilder class enables you to programmatically generate assemblies. These assemblies can be saved to a file, unlike dynamic assemblies generated by AssemblyBuilder class, which does not support saving assemblies to a file on .NET 5+ and .NET Core.
The MetadataBuilder
API operates low-level metadata constructs, such as tables or blobs. For a simpler way to generate assemblies dynamically using C#, see CSharpCompilation in Roslyn API.
The format of CLI metadata is defined by the ECMA-335 specification. For more information, see Standard ECMA-335 - Common Language Infrastructure (CLI) on the Ecma International Web site.
Metadata |
Creates a builder for metadata tables and heaps. |
Product | Versions |
---|---|
.NET | Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8 (package-provided), 8, 9 (package-provided), 9 |
.NET Framework | 4.7 (package-provided), 4.7.1 (package-provided), 4.7.2 (package-provided), 4.8 (package-provided) |
.NET Standard | 2.0 (package-provided) |
.NET feedback
.NET is an open source project. Select a link to provide feedback: