Overview
In the Common Language Runtime (CLR), metadata is data that describes the structure of an assembly. It contains information about types, members, references, and security attributes, enabling the CLR to enforce type safety, perform reflection, and support language interoperability.
Metadata is stored in a binary format defined by the ECMA-335 Common Language Infrastructure (CLI) specification. When you compile a .NET source file, the compiler emits a Portable Executable (PE) file that includes both IL code and the associated metadata.
Types of Metadata
- Assembly Metadata – Name, version, culture, public key token.
- Module Metadata – Namespaces, types, and the logical layout of the assembly.
- Type Metadata – Definitions of classes, structs, enums, interfaces, delegates.
- Member Metadata – Methods, fields, properties, events, constructors.
- Custom Attribute Metadata – User-defined attributes applied to any metadata element.
Metadata Tables
The CLR stores metadata in a series of tables, each containing rows that represent a particular kind of entity. Below is a simplified view of the most common tables:
Table Name Description
-------------- ------------------------------
Assembly Assembly identity
Module Module identity
TypeDef Defined types (class, struct, etc.)
MethodDef Defined methods
FieldDef Defined fields
Property Defined properties
Event Defined events
MemberRef References to members in other modules
CustomAttribute Custom attribute data
MethodImpl Method implementations (IL, native)
InterfaceImpl Implemented interfaces
# ... many more tables per ECMA-335 specification
Reading Metadata with Reflection
Reflection provides a high‑level API for inspecting metadata at runtime. The following C# example demonstrates how to enumerate all types in an assembly and list their public methods:
using System;
using System.Reflection;
class Program
{
static void Main()
{
Assembly asm = Assembly.Load("System.Console");
foreach (Type t in asm.GetTypes())
{
Console.WriteLine($"Type: {t.FullName}");
foreach (MethodInfo m in t.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static))
{
Console.WriteLine($" Method: {m.Name}");
}
}
}
}
Custom Attributes
Custom attributes are a powerful way to embed additional metadata. They are stored in the CustomAttribute
table and can be retrieved via reflection.
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public sealed class DocumentationAttribute : Attribute
{
public string Url { get; }
public DocumentationAttribute(string url) => Url = url;
}
[Documentation("https://learn.microsoft.com/dotnet/standard/metadata")]
public class MyClass { }
Emitting Metadata (IL)
The System.Reflection.Emit
namespace enables you to generate assemblies dynamically, including custom metadata. Below is a minimal example that creates a new assembly with a single type and method:
using System;
using System.Reflection;
using System.Reflection.Emit;
class DynamicGen
{
static void Main()
{
AssemblyName aName = new AssemblyName("DynamicDemo");
AssemblyBuilder asm = AssemblyBuilder.DefineDynamicAssembly(aName, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder mod = asm.DefineDynamicModule("MainModule", "DynamicDemo.dll");
TypeBuilder tb = mod.DefineType("HelloWorld", TypeAttributes.Public);
MethodBuilder mb = tb.DefineMethod("SayHello", MethodAttributes.Public | MethodAttributes.Static, typeof(void), Type.EmptyTypes);
ILGenerator il = mb.GetILGenerator();
il.EmitWriteLine("Hello from dynamically generated assembly!");
il.Emit(OpCodes.Ret);
tb.CreateType();
asm.Save("DynamicDemo.dll");
}
}
Metadata & Resources
In addition to type information, assemblies can contain embedded resources (images, strings, etc.). The .manifest
table references these resources, and they can be accessed at runtime via Assembly.GetManifestResourceStream
.