Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu makale, bu API'nin başvuru belgelerine ek açıklamalar sağlar.
AssemblyBuilder.Save API'si başlangıçta .NET (Core)'a taşınmadı çünkü uygulama büyük ölçüde Windows'a özgü, taşınmamış yerel koda dayanıyordu. .NET 9, tamamen yönetilen ve kaydetmeyi destekleyen bir Reflection.Emit uygulaması sağlayan PersistedAssemblyBuilder sınıfını ekledi. Bu uygulamanın önceden var olan, çalışma zamanına özgü Reflection.Emit uygulamasına bağımlılığı yoktur. Yani, artık .NET'te iki farklı uygulama vardır: çalıştırılabilir ve kalıcı. Kalıcı derlemeyi çalıştırmak için önce bir bellek akışına veya dosyaya kaydedin, sonra yeniden yükleyin.
PersistedAssemblyBuilderönce yalnızca oluşturulan bir derlemeyi çalıştırabilir ve kaydedemeyebilirsiniz. Derleme yalnızca bellek içi olduğundan hata ayıklaması zordu. Dinamik derlemeyi bir dosyaya kaydetmenin avantajları şunlardır:
- Oluşturulan derlemeyi ILVerify gibi araçlarla doğrulayabilir veya derleyip ILSpy gibi araçlarla el ile inceleyebilirsiniz.
- Kaydedilen derleme, yeniden derlenmesi gerekmeden doğrudan yüklenebilir ve bu da uygulama başlatma süresini azaltabilir.
PersistedAssemblyBuilder örneği oluşturmak için PersistedAssemblyBuilder(AssemblyName, Assembly, IEnumerable<CustomAttributeBuilder>) oluşturucuyu kullanın.
coreAssembly parametresi temel çalışma zamanı türlerini çözümlemek için kullanılır ve başvuru derlemesi sürümünü çözümlemek için kullanılabilir:
Reflection.Emityalnızca derleyicinin üzerinde çalıştığı çalışma zamanı sürümüyle (genellikle in-proc) aynı çalışma zamanı sürümünde yürütülecek bir derleme oluşturmak için kullanılırsa, çekirdek derleme yalnızcatypeof(object).Assemblyolabilir. Aşağıdaki örnekte bir derlemenin nasıl oluşturulup akışa kaydedilip geçerli çalışma zamanı derlemesiyle nasıl çalıştırılabileceği gösterilmektedir:public static void CreateSaveAndRunAssembly() { PersistedAssemblyBuilder ab = new(new AssemblyName("MyAssembly"), typeof(object).Assembly); ModuleBuilder mob = ab.DefineDynamicModule("MyModule"); TypeBuilder tb = mob.DefineType( "MyType", TypeAttributes.Public | TypeAttributes.Class); MethodBuilder meb = tb.DefineMethod( "SumMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(int), [typeof(int), typeof(int)]); ILGenerator il = meb.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Add); il.Emit(OpCodes.Ret); tb.CreateType(); using var stream = new MemoryStream(); ab.Save(stream); // Or pass filename to save into a file. stream.Seek(0, SeekOrigin.Begin); Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(stream); MethodInfo method = assembly.GetType("MyType").GetMethod("SumMethod"); Console.WriteLine(method.Invoke(null, [5, 10])); }Belirli bir TFM'yi hedefleyen bir derleme oluşturmak için
kullanılırsa, kullanarak verilen TFM için başvuru derlemelerini açın ve için metadataloadcontext.coreassembly özelliğinin değerini kullanın. Bu değer, oluşturucunun bir .NET çalışma zamanı sürümünde çalışmasına ve farklı bir .NET çalışma zamanı sürümünü hedeflemesine olanak tanır. Çekirdek türlerine başvururken MetadataLoadContextörneği tarafından döndürülen türleri kullanmanız gerekir. Örneğin,typeof(int)yerine ada göreSystem.Int32'deMetadataLoadContext.CoreAssemblytürünü bulun.public static void CreatePersistedAssemblyBuilderCoreAssemblyWithMetadataLoadContext(string refAssembliesPath) { PathAssemblyResolver resolver = new(Directory.GetFiles(refAssembliesPath, "*.dll")); using MetadataLoadContext context = new(resolver); Assembly coreAssembly = context.CoreAssembly; PersistedAssemblyBuilder ab = new(new AssemblyName("MyDynamicAssembly"), coreAssembly); TypeBuilder typeBuilder = ab.DefineDynamicModule("MyModule").DefineType("Test", TypeAttributes.Public); MethodBuilder methodBuilder = typeBuilder.DefineMethod("Method", MethodAttributes.Public, coreAssembly.GetType(typeof(int).FullName), Type.EmptyTypes); // .. add members and save the assembly }
Yürütülebilir dosya için giriş noktası ayarlama
Yürütülebilir dosyanın giriş noktasını ayarlamak veya derleme dosyası için diğer seçenekleri ayarlamak için public MetadataBuilder GenerateMetadata(out BlobBuilder ilStream, out BlobBuilder mappedFieldData) yöntemini çağırabilir ve doldurulan meta verileri kullanarak derlemeyi istenen seçeneklerle oluşturabilirsiniz, örneğin:
public static void SetEntryPoint()
{
PersistedAssemblyBuilder ab = new(new AssemblyName("MyAssembly"), typeof(object).Assembly);
TypeBuilder tb = ab.DefineDynamicModule("MyModule").DefineType("MyType", TypeAttributes.Public | TypeAttributes.Class);
// ...
MethodBuilder entryPoint = tb.DefineMethod("Main", MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Static);
ILGenerator il2 = entryPoint.GetILGenerator();
// ...
il2.Emit(OpCodes.Ret);
tb.CreateType();
MetadataBuilder metadataBuilder = ab.GenerateMetadata(out BlobBuilder ilStream, out BlobBuilder fieldData);
ManagedPEBuilder peBuilder = new(
header: PEHeaderBuilder.CreateExecutableHeader(),
metadataRootBuilder: new MetadataRootBuilder(metadataBuilder),
ilStream: ilStream,
mappedFieldData: fieldData,
entryPoint: MetadataTokens.MethodDefinitionHandle(entryPoint.MetadataToken));
BlobBuilder peBlob = new();
peBuilder.Serialize(peBlob);
// Create the executable:
using FileStream fileStream = new("MyAssembly.exe", FileMode.Create, FileAccess.Write);
peBlob.WriteContentTo(fileStream);
}
Sembolleri yayma ve PDB oluşturma
Simgelerin meta verileri, pdbBuilder örneğinde GenerateMetadata(BlobBuilder, BlobBuilder) yöntemini çağırdığınızda, PersistedAssemblyBuilder out parametresine doldurulur. Taşınabilir PDB ile derleme oluşturmak için:
- ISymbolDocumentWriter yöntemiyle ModuleBuilder.DefineDocument(String, Guid, Guid, Guid) örnekleri oluşturun. Yöntemin IL'sini yayarken, ilgili sembol bilgilerini de yayar.
-
PortablePdbBuilder yöntemi tarafından üretilen
pdbBuilderörneğini kullanarak bir GenerateMetadata(BlobBuilder, BlobBuilder) örneği oluşturun. -
PortablePdbBuilder'ı bir Blobolarak serileştirin veBlob'yi PDB dosya akışına yazın (sadece bağımsız bir PDB üretiyorsanız). - bir DebugDirectoryBuilder örneği oluşturun ve bir DebugDirectoryBuilder.AddCodeViewEntry (tek başına PDB) veya DebugDirectoryBuilder.AddEmbeddedPortablePdbEntryekleyin.
-
debugDirectoryBuilderörneği oluştururken isteğe bağlı PEBuilder bağımsız değişkenini ayarlayın.
Aşağıdaki örnekte, sembol bilgilerini yayma ve PDB dosyası oluşturma gösterilmektedir.
static void GenerateAssemblyWithPdb()
{
PersistedAssemblyBuilder ab = new PersistedAssemblyBuilder(new AssemblyName("MyAssembly"), typeof(object).Assembly);
ModuleBuilder mb = ab.DefineDynamicModule("MyModule");
TypeBuilder tb = mb.DefineType("MyType", TypeAttributes.Public | TypeAttributes.Class);
MethodBuilder mb1 = tb.DefineMethod("SumMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(int), [typeof(int), typeof(int)]);
ISymbolDocumentWriter srcDoc = mb.DefineDocument("MySourceFile.cs", SymLanguageType.CSharp);
ILGenerator il = mb1.GetILGenerator();
LocalBuilder local = il.DeclareLocal(typeof(int));
local.SetLocalSymInfo("myLocal");
il.MarkSequencePoint(srcDoc, 7, 0, 7, 11);
...
il.Emit(OpCodes.Ret);
MethodBuilder entryPoint = tb.DefineMethod("Main", MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Static);
ILGenerator il2 = entryPoint.GetILGenerator();
il2.BeginScope();
...
il2.EndScope();
...
tb.CreateType();
MetadataBuilder metadataBuilder = ab.GenerateMetadata(out BlobBuilder ilStream, out _, out MetadataBuilder pdbBuilder);
MethodDefinitionHandle entryPointHandle = MetadataTokens.MethodDefinitionHandle(entryPoint.MetadataToken);
DebugDirectoryBuilder debugDirectoryBuilder = GeneratePdb(pdbBuilder, metadataBuilder.GetRowCounts(), entryPointHandle);
ManagedPEBuilder peBuilder = new ManagedPEBuilder(
header: new PEHeaderBuilder(imageCharacteristics: Characteristics.ExecutableImage, subsystem: Subsystem.WindowsCui),
metadataRootBuilder: new MetadataRootBuilder(metadataBuilder),
ilStream: ilStream,
debugDirectoryBuilder: debugDirectoryBuilder,
entryPoint: entryPointHandle);
BlobBuilder peBlob = new BlobBuilder();
peBuilder.Serialize(peBlob);
using var fileStream = new FileStream("MyAssembly.exe", FileMode.Create, FileAccess.Write);
peBlob.WriteContentTo(fileStream);
}
static DebugDirectoryBuilder GeneratePdb(MetadataBuilder pdbBuilder, ImmutableArray<int> rowCounts, MethodDefinitionHandle entryPointHandle)
{
BlobBuilder portablePdbBlob = new BlobBuilder();
PortablePdbBuilder portablePdbBuilder = new PortablePdbBuilder(pdbBuilder, rowCounts, entryPointHandle);
BlobContentId pdbContentId = portablePdbBuilder.Serialize(portablePdbBlob);
// In case saving PDB to a file
using FileStream fileStream = new FileStream("MyAssemblyEmbeddedSource.pdb", FileMode.Create, FileAccess.Write);
portablePdbBlob.WriteContentTo(fileStream);
DebugDirectoryBuilder debugDirectoryBuilder = new DebugDirectoryBuilder();
debugDirectoryBuilder.AddCodeViewEntry("MyAssemblyEmbeddedSource.pdb", pdbContentId, portablePdbBuilder.FormatVersion);
// In case embedded in PE:
// debugDirectoryBuilder.AddEmbeddedPortablePdbEntry(portablePdbBlob, portablePdbBuilder.FormatVersion);
return debugDirectoryBuilder;
}
Ayrıca, kaynak ekleme ve kaynak dizin oluşturma gelişmiş PDB bilgileri eklemek için CustomDebugInformation örneğinden MetadataBuilder.AddCustomDebugInformation(EntityHandle, GuidHandle, BlobHandle) yöntemini çağırarak pdbBuilder ekleyebilirsiniz.
private static void EmbedSource(MetadataBuilder pdbBuilder)
{
byte[] sourceBytes = File.ReadAllBytes("MySourceFile2.cs");
BlobBuilder sourceBlob = new BlobBuilder();
sourceBlob.WriteBytes(sourceBytes);
pdbBuilder.AddCustomDebugInformation(MetadataTokens.DocumentHandle(1),
pdbBuilder.GetOrAddGuid(new Guid("0E8A571B-6926-466E-B4AD-8AB04611F5FE")), pdbBuilder.GetOrAddBlob(sourceBlob));
}
PersistedAssemblyBuilder ile kaynak ekleme
MetadataBuilder.AddManifestResource(ManifestResourceAttributes, StringHandle, EntityHandle, UInt32) çağırarak gerektiği kadar kaynak ekleyebilirsiniz. Akışlar, BlobBuilder bağımsız değişkenine geçirdiğiniz tek bir ManagedPEBuilder olarak birleştirilmelidir. Aşağıdaki örnek, kaynakların nasıl oluşturulacağını ve oluşturulan derlemeye nasıl eklendiğini gösterir.
public static void SetResource()
{
PersistedAssemblyBuilder ab = new(new AssemblyName("MyAssembly"), typeof(object).Assembly);
ab.DefineDynamicModule("MyModule");
MetadataBuilder metadata = ab.GenerateMetadata(out BlobBuilder ilStream, out _);
using MemoryStream stream = new();
ResourceWriter myResourceWriter = new(stream);
myResourceWriter.AddResource("AddResource 1", "First added resource");
myResourceWriter.AddResource("AddResource 2", "Second added resource");
myResourceWriter.AddResource("AddResource 3", "Third added resource");
myResourceWriter.Close();
byte[] data = stream.ToArray();
BlobBuilder resourceBlob = new();
resourceBlob.WriteInt32(data.Length);
resourceBlob.WriteBytes(data);
metadata.AddManifestResource(
ManifestResourceAttributes.Public,
metadata.GetOrAddString("MyResource.resources"),
implementation: default,
offset: 0);
ManagedPEBuilder peBuilder = new(
header: PEHeaderBuilder.CreateLibraryHeader(),
metadataRootBuilder: new MetadataRootBuilder(metadata),
ilStream: ilStream,
managedResources: resourceBlob);
BlobBuilder blob = new();
peBuilder.Serialize(blob);
// Create the assembly:
using FileStream fileStream = new("MyAssemblyWithResource.dll", FileMode.Create, FileAccess.Write);
blob.WriteContentTo(fileStream);
}
Aşağıdaki örnekte, oluşturulan derlemedeki kaynakların nasıl okunduğu gösterilmektedir.
public static void ReadResource()
{
Assembly readAssembly = Assembly.LoadFile(Path.Combine(
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
"MyAssemblyWithResource.dll"));
// Use ResourceManager.GetString() to read the resources.
ResourceManager rm = new("MyResource", readAssembly);
Console.WriteLine("Using ResourceManager.GetString():");
Console.WriteLine($"{rm.GetString("AddResource 1", CultureInfo.InvariantCulture)}");
Console.WriteLine($"{rm.GetString("AddResource 2", CultureInfo.InvariantCulture)}");
Console.WriteLine($"{rm.GetString("AddResource 3", CultureInfo.InvariantCulture)}");
// Use ResourceSet to enumerate the resources.
Console.WriteLine();
Console.WriteLine("Using ResourceSet:");
ResourceSet resourceSet = rm.GetResourceSet(CultureInfo.InvariantCulture, createIfNotExists: true, tryParents: false);
foreach (DictionaryEntry entry in resourceSet)
{
Console.WriteLine($"Key: {entry.Key}, Value: {entry.Value}");
}
// Use ResourceReader to enumerate the resources.
Console.WriteLine();
Console.WriteLine("Using ResourceReader:");
using Stream stream = readAssembly.GetManifestResourceStream("MyResource.resources")!;
using ResourceReader reader = new(stream);
foreach (DictionaryEntry entry in reader)
{
Console.WriteLine($"Key: {entry.Key}, Value: {entry.Value}");
}
}
Not Alın
Tüm üyeler için meta veri belirteçleri Save işleminde doldurulur. Varsayılan değerlere sahip olacak veya özel durumlar oluşturacaklarından, kaydetmeden önce oluşturulan türün belirteçlerini ve üyelerini kullanmayın. Başvuruda kullanılan, üretilmeyen türler için belirteç kullanmak güvenlidir.
Derleme yayma açısından önemli olmayan bazı API'ler uygulanmaz; örneğin, GetCustomAttributes() uygulanmaz. Çalışma zamanı uygulamasıyla, türü oluşturduktan sonra bu API'leri kullanabildiniz. Kalıcı AssemblyBuilderiçin NotSupportedException veya NotImplementedExceptionatarlar. Bu API'leri gerektiren bir senaryonuz varsa, dotnet/runtime deposundabir sorun oluşturun.
Derleme dosyaları oluşturmanın alternatif bir yolu için bkz. MetadataBuilder.