Replace the legacy EventBase runtime with generated multi-bus bindings and explicit scheduling. Migrate app, data, network, demo, and mod consumers; add generated network-event registration and owner-scoped mod content overrides.
530 lines
26 KiB
C#
530 lines
26 KiB
C#
#nullable enable
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using Mono.Cecil;
|
|
using Mono.Cecil.Cil;
|
|
using Mono.Cecil.Rocks;
|
|
using Mono.Cecil.Pdb;
|
|
using Unity.CompilationPipeline.Common.Diagnostics;
|
|
using Unity.CompilationPipeline.Common.ILPostProcessing;
|
|
|
|
namespace ShrinkEventBus.CodeGen
|
|
{
|
|
public sealed class EventBusILPostProcessor : ILPostProcessor
|
|
{
|
|
private const string RuntimeAssemblyName = "ShrinkEventBus.Runtime";
|
|
public override ILPostProcessor GetInstance() => this;
|
|
|
|
public override bool WillProcess(ICompiledAssembly compiledAssembly)
|
|
{
|
|
if (!ReferencesAssembly(compiledAssembly, RuntimeAssemblyName))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly)
|
|
{
|
|
var diagnostics = new List<DiagnosticMessage>();
|
|
if (!WillProcess(compiledAssembly))
|
|
return new ILPostProcessResult(compiledAssembly.InMemoryAssembly, diagnostics);
|
|
|
|
var assemblyDefinition = AssemblyDefinitionFor(compiledAssembly);
|
|
var module = assemblyDefinition.MainModule;
|
|
|
|
try
|
|
{
|
|
var generatedSubscriberType = FindType(module, "ShrinkEventBus.ShrinkEventSubscriberAttribute", RuntimeAssemblyName);
|
|
var generatedSubscribeType = FindType(module, "ShrinkEventBus.ShrinkSubscribeAttribute", RuntimeAssemblyName);
|
|
if (generatedSubscriberType == null || generatedSubscribeType == null)
|
|
return GetResult(assemblyDefinition, diagnostics);
|
|
|
|
foreach (var type in GetAllTypes(module.Types)
|
|
.Where(type => !type.IsInterface && !type.IsAbstract)
|
|
.Where(type => HasAttribute(type, generatedSubscriberType))
|
|
.Where(type => type.Methods.Any(method =>
|
|
!method.IsStatic && HasAttribute(method, generatedSubscribeType))))
|
|
{
|
|
InjectGeneratedBinding(type, module, generatedSubscribeType);
|
|
}
|
|
|
|
var staticSubscriberTypes = GetAllTypes(module.Types)
|
|
.Where(type => HasAttribute(type, generatedSubscriberType))
|
|
.Where(type => type.Methods.Any(method =>
|
|
method.IsStatic && HasAttribute(method, generatedSubscribeType)))
|
|
.ToArray();
|
|
if (staticSubscriberTypes.Length > 0)
|
|
InjectStaticBootstrap(module, staticSubscriberTypes, generatedSubscribeType);
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
diagnostics.Add(new DiagnosticMessage
|
|
{
|
|
DiagnosticType = DiagnosticType.Error,
|
|
MessageData = $"[ShrinkEventBus.CodeGen] {ex.Message}"
|
|
});
|
|
}
|
|
|
|
return GetResult(assemblyDefinition, diagnostics);
|
|
}
|
|
|
|
private static bool ReferencesAssembly(ICompiledAssembly compiledAssembly, string assemblyName)
|
|
{
|
|
return compiledAssembly.References.Any(reference =>
|
|
string.Equals(Path.GetFileNameWithoutExtension(reference), assemblyName, StringComparison.Ordinal));
|
|
}
|
|
|
|
private static bool HasAttribute(ICustomAttributeProvider provider, TypeReference expectedAttributeType)
|
|
{
|
|
return provider.CustomAttributes.Any(attribute => attribute.AttributeType.FullName == expectedAttributeType.FullName);
|
|
}
|
|
|
|
private static IEnumerable<TypeDefinition> GetAllTypes(IEnumerable<TypeDefinition> roots)
|
|
{
|
|
foreach (var type in roots)
|
|
{
|
|
yield return type;
|
|
foreach (var nested in GetAllTypes(type.NestedTypes))
|
|
yield return nested;
|
|
}
|
|
}
|
|
|
|
private static void InjectGeneratedBinding(TypeDefinition type, ModuleDefinition module,
|
|
TypeReference subscribeAttributeType)
|
|
{
|
|
var generatedInterface = FindType(module,
|
|
"ShrinkEventBus.IShrinkGeneratedSubscriber", RuntimeAssemblyName)
|
|
?? throw new InvalidOperationException("IShrinkGeneratedSubscriber was not found.");
|
|
if (type.Interfaces.Any(item => item.InterfaceType.FullName == generatedInterface.FullName))
|
|
return;
|
|
|
|
var resolverType = FindType(module, "ShrinkEventBus.IShrinkBusResolver", RuntimeAssemblyName)
|
|
?? throw new InvalidOperationException("IShrinkBusResolver was not found.");
|
|
var busKeyType = FindType(module, "ShrinkEventBus.ShrinkBusKey", RuntimeAssemblyName)
|
|
?? throw new InvalidOperationException("ShrinkBusKey was not found.");
|
|
var bindingType = FindType(module, "ShrinkEventBus.ShrinkEventBinding", RuntimeAssemblyName)
|
|
?? throw new InvalidOperationException("ShrinkEventBinding was not found.");
|
|
var bindingHelperType = FindType(module, "ShrinkEventBus.ShrinkGeneratedBinding", RuntimeAssemblyName)
|
|
?? throw new InvalidOperationException("ShrinkGeneratedBinding was not found.");
|
|
var priorityType = FindType(module, "ShrinkEventBus.ShrinkEventPriority", RuntimeAssemblyName)
|
|
?? throw new InvalidOperationException("ShrinkEventPriority was not found.");
|
|
var asyncHandlerType = FindType(module, "ShrinkEventBus.ShrinkAsyncEventHandler`1", RuntimeAssemblyName)
|
|
?? throw new InvalidOperationException("ShrinkAsyncEventHandler was not found.");
|
|
|
|
var nullableBusKey = new GenericInstanceType(module.ImportReference(typeof(Nullable<>)));
|
|
nullableBusKey.GenericArguments.Add(busKeyType);
|
|
var disposableType = module.ImportReference(typeof(IDisposable));
|
|
var bindingDefinition = bindingType.Resolve()
|
|
?? throw new InvalidOperationException("ShrinkEventBinding could not be resolved.");
|
|
var bindingCtor = module.ImportReference(bindingDefinition.Methods.Single(method =>
|
|
method.IsConstructor && method.Parameters.Count == 0));
|
|
var bindingAdd = module.ImportReference(bindingDefinition.Methods.Single(method =>
|
|
method.Name == "Add" && method.Parameters.Count == 1));
|
|
|
|
var helperDefinition = bindingHelperType.Resolve()
|
|
?? throw new InvalidOperationException("ShrinkGeneratedBinding could not be resolved.");
|
|
var syncSubscribe = module.ImportReference(helperDefinition.Methods.Single(method =>
|
|
method.Name == "Subscribe" && method.HasGenericParameters));
|
|
var asyncSubscribe = module.ImportReference(helperDefinition.Methods.Single(method =>
|
|
method.Name == "SubscribeAsync" && method.HasGenericParameters));
|
|
var legacyAsyncSubscribe = module.ImportReference(helperDefinition.Methods.Single(method =>
|
|
method.Name == "SubscribeAsyncLegacy" && method.HasGenericParameters));
|
|
|
|
var interfaceDefinition = generatedInterface.Resolve()
|
|
?? throw new InvalidOperationException("IShrinkGeneratedSubscriber could not be resolved.");
|
|
var interfaceMethod = module.ImportReference(interfaceDefinition.Methods.Single(method =>
|
|
method.Name == "AttachGenerated"));
|
|
|
|
var generatedMethod = new MethodDefinition(
|
|
"ShrinkEventBus.IShrinkGeneratedSubscriber.AttachGenerated",
|
|
MethodAttributes.Private | MethodAttributes.Final | MethodAttributes.HideBySig |
|
|
MethodAttributes.NewSlot | MethodAttributes.Virtual,
|
|
disposableType);
|
|
generatedMethod.Parameters.Add(new ParameterDefinition("resolver", ParameterAttributes.None, resolverType));
|
|
generatedMethod.Parameters.Add(new ParameterDefinition("defaultBus", ParameterAttributes.Optional,
|
|
nullableBusKey));
|
|
generatedMethod.Overrides.Add(interfaceMethod);
|
|
generatedMethod.Body.InitLocals = true;
|
|
var bindingLocal = new VariableDefinition(bindingType);
|
|
generatedMethod.Body.Variables.Add(bindingLocal);
|
|
var il = generatedMethod.Body.GetILProcessor();
|
|
il.Emit(OpCodes.Newobj, bindingCtor);
|
|
il.Emit(OpCodes.Stloc, bindingLocal);
|
|
|
|
var classDefaultBus = ReadStringProperty(
|
|
type.CustomAttributes.First(attribute =>
|
|
attribute.AttributeType.FullName == "ShrinkEventBus.ShrinkEventSubscriberAttribute"),
|
|
"DefaultBus");
|
|
|
|
foreach (var handler in type.Methods.Where(method =>
|
|
!method.IsStatic && HasAttribute(method, subscribeAttributeType)).ToArray())
|
|
{
|
|
EmitGeneratedSubscription(il, module, type, handler,
|
|
handler.CustomAttributes.First(attribute =>
|
|
attribute.AttributeType.FullName == subscribeAttributeType.FullName),
|
|
classDefaultBus, bindingLocal, bindingAdd, syncSubscribe, asyncSubscribe,
|
|
legacyAsyncSubscribe, asyncHandlerType);
|
|
}
|
|
|
|
il.Emit(OpCodes.Ldloc, bindingLocal);
|
|
il.Emit(OpCodes.Ret);
|
|
type.Interfaces.Add(new InterfaceImplementation(generatedInterface));
|
|
type.Methods.Add(generatedMethod);
|
|
}
|
|
|
|
private static void EmitGeneratedSubscription(ILProcessor il, ModuleDefinition module,
|
|
TypeDefinition ownerType, MethodDefinition handler, CustomAttribute attribute,
|
|
string classDefaultBus, VariableDefinition bindingLocal, MethodReference bindingAdd,
|
|
MethodReference syncSubscribe, MethodReference asyncSubscribe,
|
|
MethodReference legacyAsyncSubscribe, TypeReference asyncHandlerType)
|
|
{
|
|
if (handler.Parameters.Count is < 1 or > 2)
|
|
throw new InvalidOperationException(
|
|
$"[ShrinkSubscribe] method {handler.FullName} must have one event parameter and an optional CancellationToken.");
|
|
|
|
var eventType = module.ImportReference(handler.Parameters[0].ParameterType);
|
|
var eventInterface = FindType(module, "ShrinkEventBus.IShrinkEvent", RuntimeAssemblyName)
|
|
?? throw new InvalidOperationException("IShrinkEvent was not found.");
|
|
if (!ImplementsInterface(eventType, eventInterface.FullName))
|
|
throw new InvalidOperationException(
|
|
$"[ShrinkSubscribe] method {handler.FullName} event parameter must implement IShrinkEvent.");
|
|
|
|
var bus = ReadStringProperty(attribute, "Bus");
|
|
if (string.IsNullOrWhiteSpace(bus))
|
|
bus = classDefaultBus;
|
|
var priority = ReadIntProperty(attribute, "Priority", 2);
|
|
var numericPriority = ReadIntProperty(attribute, "NumericPriority", 0);
|
|
var receiveCanceled = ReadBoolProperty(attribute, "ReceiveCanceled", false);
|
|
|
|
MethodReference openSubscribe;
|
|
TypeReference delegateType;
|
|
if (handler.ReturnType.FullName == module.TypeSystem.Void.FullName && handler.Parameters.Count == 1)
|
|
{
|
|
openSubscribe = syncSubscribe;
|
|
delegateType = MakeGenericType(module, typeof(Action<>), eventType);
|
|
}
|
|
else if (handler.ReturnType.FullName == "Cysharp.Threading.Tasks.UniTask" &&
|
|
handler.Parameters.Count == 1)
|
|
{
|
|
openSubscribe = legacyAsyncSubscribe;
|
|
var uniTaskType = FindType(module, "Cysharp.Threading.Tasks.UniTask", "UniTask")
|
|
?? module.ImportReference(handler.ReturnType);
|
|
delegateType = MakeGenericType(module, typeof(Func<,>), eventType, uniTaskType);
|
|
}
|
|
else if (handler.ReturnType.FullName == "Cysharp.Threading.Tasks.UniTask" &&
|
|
handler.Parameters.Count == 2 &&
|
|
handler.Parameters[1].ParameterType.FullName == typeof(System.Threading.CancellationToken).FullName)
|
|
{
|
|
openSubscribe = asyncSubscribe;
|
|
var closedAsyncHandler = new GenericInstanceType(asyncHandlerType);
|
|
closedAsyncHandler.GenericArguments.Add(eventType);
|
|
delegateType = closedAsyncHandler;
|
|
}
|
|
else
|
|
{
|
|
throw new InvalidOperationException(
|
|
$"Unsupported [ShrinkSubscribe] signature: {handler.FullName}. Use void(T), UniTask(T), or UniTask(T, CancellationToken).");
|
|
}
|
|
|
|
var closedSubscribe = new GenericInstanceMethod(openSubscribe);
|
|
closedSubscribe.GenericArguments.Add(eventType);
|
|
var delegateCtor = MakeDelegateConstructor(module, delegateType);
|
|
|
|
il.Emit(OpCodes.Ldloc, bindingLocal);
|
|
il.Emit(OpCodes.Ldarg_1);
|
|
il.Emit(OpCodes.Ldarg_2);
|
|
il.Emit(OpCodes.Ldstr, bus ?? string.Empty);
|
|
il.Emit(OpCodes.Ldarg_0);
|
|
il.Emit(OpCodes.Ldarg_0);
|
|
il.Emit(OpCodes.Ldftn, module.ImportReference(handler));
|
|
il.Emit(OpCodes.Newobj, delegateCtor);
|
|
il.Emit(OpCodes.Ldc_I4, priority);
|
|
il.Emit(OpCodes.Ldc_I4, numericPriority);
|
|
il.Emit(receiveCanceled ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
|
|
il.Emit(OpCodes.Call, closedSubscribe);
|
|
il.Emit(OpCodes.Callvirt, bindingAdd);
|
|
}
|
|
|
|
private static void InjectStaticBootstrap(ModuleDefinition module,
|
|
IReadOnlyList<TypeDefinition> subscriberTypes, TypeReference subscribeAttributeType)
|
|
{
|
|
var registryType = FindType(module, "ShrinkEventBus.ShrinkStaticBindingRegistry", RuntimeAssemblyName)
|
|
?? throw new InvalidOperationException("ShrinkStaticBindingRegistry was not found.");
|
|
var asyncHandlerType = FindType(module, "ShrinkEventBus.ShrinkAsyncEventHandler`1", RuntimeAssemblyName)
|
|
?? throw new InvalidOperationException("ShrinkAsyncEventHandler was not found.");
|
|
var registryDefinition = registryType.Resolve()
|
|
?? throw new InvalidOperationException("ShrinkStaticBindingRegistry could not be resolved.");
|
|
var syncRegister = module.ImportReference(registryDefinition.Methods.Single(method =>
|
|
method.Name == "Register" && method.HasGenericParameters));
|
|
var asyncRegister = module.ImportReference(registryDefinition.Methods.Single(method =>
|
|
method.Name == "RegisterAsync" && method.HasGenericParameters));
|
|
var legacyAsyncRegister = module.ImportReference(registryDefinition.Methods.Single(method =>
|
|
method.Name == "RegisterAsyncLegacy" && method.HasGenericParameters));
|
|
|
|
var bootstrap = new TypeDefinition("ShrinkEventBus.Generated",
|
|
"ShrinkGeneratedStaticBindings",
|
|
TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.NotPublic,
|
|
module.TypeSystem.Object);
|
|
module.Types.Add(bootstrap);
|
|
|
|
var register = new MethodDefinition("Register",
|
|
MethodAttributes.Assembly | MethodAttributes.Static | MethodAttributes.HideBySig,
|
|
module.TypeSystem.Void);
|
|
bootstrap.Methods.Add(register);
|
|
var il = register.Body.GetILProcessor();
|
|
|
|
foreach (var type in subscriberTypes)
|
|
{
|
|
var classDefaultBus = ReadStringProperty(
|
|
type.CustomAttributes.First(attribute =>
|
|
attribute.AttributeType.FullName == "ShrinkEventBus.ShrinkEventSubscriberAttribute"),
|
|
"DefaultBus");
|
|
foreach (var handler in type.Methods.Where(method =>
|
|
method.IsStatic && HasAttribute(method, subscribeAttributeType)).ToArray())
|
|
{
|
|
EmitStaticGeneratedSubscription(il, module, handler,
|
|
handler.CustomAttributes.First(attribute =>
|
|
attribute.AttributeType.FullName == subscribeAttributeType.FullName),
|
|
classDefaultBus, syncRegister, asyncRegister,
|
|
legacyAsyncRegister, asyncHandlerType);
|
|
}
|
|
}
|
|
|
|
il.Emit(OpCodes.Ret);
|
|
InjectModuleInitializer(module, register);
|
|
}
|
|
|
|
private static void EmitStaticGeneratedSubscription(ILProcessor il, ModuleDefinition module,
|
|
MethodDefinition handler, CustomAttribute attribute, string classDefaultBus,
|
|
MethodReference syncRegister, MethodReference asyncRegister,
|
|
MethodReference legacyAsyncRegister, TypeReference asyncHandlerType)
|
|
{
|
|
if (handler.Parameters.Count is < 1 or > 2)
|
|
throw new InvalidOperationException(
|
|
$"[ShrinkSubscribe] method {handler.FullName} must have one event parameter and an optional CancellationToken.");
|
|
|
|
var eventType = module.ImportReference(handler.Parameters[0].ParameterType);
|
|
var eventInterface = FindType(module, "ShrinkEventBus.IShrinkEvent", RuntimeAssemblyName)
|
|
?? throw new InvalidOperationException("IShrinkEvent was not found.");
|
|
if (!ImplementsInterface(eventType, eventInterface.FullName))
|
|
throw new InvalidOperationException(
|
|
$"[ShrinkSubscribe] method {handler.FullName} event parameter must implement IShrinkEvent.");
|
|
|
|
var bus = ReadStringProperty(attribute, "Bus");
|
|
if (string.IsNullOrWhiteSpace(bus))
|
|
bus = classDefaultBus;
|
|
var priority = ReadIntProperty(attribute, "Priority", 2);
|
|
var numericPriority = ReadIntProperty(attribute, "NumericPriority", 0);
|
|
var receiveCanceled = ReadBoolProperty(attribute, "ReceiveCanceled", false);
|
|
|
|
MethodReference openRegister;
|
|
TypeReference delegateType;
|
|
if (handler.ReturnType.FullName == module.TypeSystem.Void.FullName && handler.Parameters.Count == 1)
|
|
{
|
|
openRegister = syncRegister;
|
|
delegateType = MakeGenericType(module, typeof(Action<>), eventType);
|
|
}
|
|
else if (handler.ReturnType.FullName == "Cysharp.Threading.Tasks.UniTask" &&
|
|
handler.Parameters.Count == 1)
|
|
{
|
|
openRegister = legacyAsyncRegister;
|
|
var uniTaskType = FindType(module, "Cysharp.Threading.Tasks.UniTask", "UniTask")
|
|
?? module.ImportReference(handler.ReturnType);
|
|
delegateType = MakeGenericType(module, typeof(Func<,>), eventType, uniTaskType);
|
|
}
|
|
else if (handler.ReturnType.FullName == "Cysharp.Threading.Tasks.UniTask" &&
|
|
handler.Parameters.Count == 2 &&
|
|
handler.Parameters[1].ParameterType.FullName == typeof(System.Threading.CancellationToken).FullName)
|
|
{
|
|
openRegister = asyncRegister;
|
|
var closedAsyncHandler = new GenericInstanceType(asyncHandlerType);
|
|
closedAsyncHandler.GenericArguments.Add(eventType);
|
|
delegateType = closedAsyncHandler;
|
|
}
|
|
else
|
|
{
|
|
throw new InvalidOperationException(
|
|
$"Unsupported static [ShrinkSubscribe] signature: {handler.FullName}.");
|
|
}
|
|
|
|
var closedRegister = new GenericInstanceMethod(openRegister);
|
|
closedRegister.GenericArguments.Add(eventType);
|
|
var delegateCtor = MakeDelegateConstructor(module, delegateType);
|
|
var handlerBridge = CreateStaticHandlerBridge(module, handler);
|
|
|
|
il.Emit(OpCodes.Ldstr, bus ?? string.Empty);
|
|
il.Emit(OpCodes.Ldnull);
|
|
il.Emit(OpCodes.Ldftn, module.ImportReference(handlerBridge));
|
|
il.Emit(OpCodes.Newobj, delegateCtor);
|
|
il.Emit(OpCodes.Ldc_I4, priority);
|
|
il.Emit(OpCodes.Ldc_I4, numericPriority);
|
|
il.Emit(receiveCanceled ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
|
|
il.Emit(OpCodes.Call, closedRegister);
|
|
}
|
|
|
|
private static MethodDefinition CreateStaticHandlerBridge(ModuleDefinition module,
|
|
MethodDefinition handler)
|
|
{
|
|
var bridge = new MethodDefinition(
|
|
$"ShrinkEventBus.GeneratedStaticHandler_{handler.MetadataToken.ToInt32():X8}",
|
|
MethodAttributes.Assembly | MethodAttributes.Static | MethodAttributes.HideBySig,
|
|
module.ImportReference(handler.ReturnType));
|
|
for (var i = 0; i < handler.Parameters.Count; i++)
|
|
{
|
|
var parameter = handler.Parameters[i];
|
|
bridge.Parameters.Add(new ParameterDefinition(parameter.Name, parameter.Attributes,
|
|
module.ImportReference(parameter.ParameterType)));
|
|
}
|
|
|
|
var il = bridge.Body.GetILProcessor();
|
|
for (var i = 0; i < bridge.Parameters.Count; i++)
|
|
il.Emit(OpCodes.Ldarg, bridge.Parameters[i]);
|
|
il.Emit(OpCodes.Call, module.ImportReference(handler));
|
|
il.Emit(OpCodes.Ret);
|
|
handler.DeclaringType.Methods.Add(bridge);
|
|
return bridge;
|
|
}
|
|
|
|
private static void InjectModuleInitializer(ModuleDefinition module, MethodReference register)
|
|
{
|
|
var moduleType = module.Types.First(type => type.Name == "<Module>");
|
|
var initializer = moduleType.Methods.FirstOrDefault(method => method.Name == ".cctor");
|
|
if (initializer == null)
|
|
{
|
|
initializer = new MethodDefinition(".cctor",
|
|
MethodAttributes.Private | MethodAttributes.Static |
|
|
MethodAttributes.HideBySig | MethodAttributes.SpecialName |
|
|
MethodAttributes.RTSpecialName,
|
|
module.TypeSystem.Void);
|
|
initializer.Body.GetILProcessor().Emit(OpCodes.Ret);
|
|
moduleType.Methods.Add(initializer);
|
|
}
|
|
|
|
var processor = initializer.Body.GetILProcessor();
|
|
processor.InsertBefore(initializer.Body.Instructions[0],
|
|
processor.Create(OpCodes.Call, register));
|
|
}
|
|
|
|
private static GenericInstanceType MakeGenericType(ModuleDefinition module, Type openType,
|
|
params TypeReference[] arguments)
|
|
{
|
|
var result = new GenericInstanceType(module.ImportReference(openType));
|
|
foreach (var argument in arguments)
|
|
result.GenericArguments.Add(argument);
|
|
return result;
|
|
}
|
|
|
|
private static MethodReference MakeDelegateConstructor(ModuleDefinition module, TypeReference delegateType)
|
|
{
|
|
var ctor = new MethodReference(".ctor", module.TypeSystem.Void, delegateType)
|
|
{
|
|
HasThis = true,
|
|
CallingConvention = MethodCallingConvention.Default
|
|
};
|
|
ctor.Parameters.Add(new ParameterDefinition(module.TypeSystem.Object));
|
|
ctor.Parameters.Add(new ParameterDefinition(module.TypeSystem.IntPtr));
|
|
return ctor;
|
|
}
|
|
|
|
private static bool ImplementsInterface(TypeReference type, string interfaceFullName)
|
|
{
|
|
TypeDefinition? current;
|
|
try
|
|
{
|
|
current = type.Resolve();
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
|
|
while (current != null)
|
|
{
|
|
if (current.Interfaces.Any(item => item.InterfaceType.FullName == interfaceFullName))
|
|
return true;
|
|
try
|
|
{
|
|
current = current.BaseType?.Resolve();
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static string ReadStringProperty(CustomAttribute attribute, string name)
|
|
{
|
|
foreach (var property in attribute.Properties)
|
|
{
|
|
if (property.Name == name)
|
|
return property.Argument.Value as string ?? string.Empty;
|
|
}
|
|
return string.Empty;
|
|
}
|
|
|
|
private static int ReadIntProperty(CustomAttribute attribute, string name, int defaultValue)
|
|
{
|
|
foreach (var property in attribute.Properties)
|
|
{
|
|
if (property.Name == name)
|
|
return Convert.ToInt32(property.Argument.Value);
|
|
}
|
|
return defaultValue;
|
|
}
|
|
|
|
private static bool ReadBoolProperty(CustomAttribute attribute, string name, bool defaultValue)
|
|
{
|
|
foreach (var property in attribute.Properties)
|
|
{
|
|
if (property.Name == name)
|
|
return Convert.ToBoolean(property.Argument.Value);
|
|
}
|
|
return defaultValue;
|
|
}
|
|
|
|
private static TypeReference? FindType(ModuleDefinition module, string fullName, string assemblyName)
|
|
{
|
|
var resolved = Type.GetType($"{fullName}, {assemblyName}", false);
|
|
return resolved == null ? null : module.ImportReference(resolved);
|
|
}
|
|
|
|
private static AssemblyDefinition AssemblyDefinitionFor(ICompiledAssembly compiledAssembly)
|
|
{
|
|
var assemblyResolver = new PostProcessorAssemblyResolver(compiledAssembly);
|
|
var readerParameters = new ReaderParameters
|
|
{
|
|
SymbolStream = new MemoryStream(compiledAssembly.InMemoryAssembly.PdbData.ToArray()),
|
|
SymbolReaderProvider = new PdbReaderProvider(),
|
|
AssemblyResolver = assemblyResolver,
|
|
ReflectionImporterProvider = new PostProcessorReflectionImporterProvider(),
|
|
ReadingMode = ReadingMode.Immediate
|
|
};
|
|
|
|
var assemblyDefinition = AssemblyDefinition.ReadAssembly(
|
|
new MemoryStream(compiledAssembly.InMemoryAssembly.PeData.ToArray()),
|
|
readerParameters);
|
|
assemblyResolver.AddAssemblyDefinitionBeingOperatedOn(assemblyDefinition);
|
|
return assemblyDefinition;
|
|
}
|
|
|
|
private static ILPostProcessResult GetResult(AssemblyDefinition assemblyDefinition, List<DiagnosticMessage> diagnostics)
|
|
{
|
|
var pe = new MemoryStream();
|
|
var pdb = new MemoryStream();
|
|
assemblyDefinition.Write(pe, new WriterParameters
|
|
{
|
|
SymbolWriterProvider = new PdbWriterProvider(),
|
|
SymbolStream = pdb,
|
|
WriteSymbols = true
|
|
});
|
|
return new ILPostProcessResult(new InMemoryAssembly(pe.ToArray(), pdb.ToArray()), diagnostics);
|
|
}
|
|
}
|
|
}
|