将 Reflection.Emit 转换为 Roslyn
Convert Reflection.Emit to Roslyn
我需要将使用 Reflection.Emit 的现有代码转换为 Roslyn。
我目前的代码基本是这样的:
var assemblyName = new AssemblyName("AssemblyName");
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
var builder = assemblyBuilder.DefineDynamicModule("test", "test.dll");
var type = builder.DefineType("Entry", TypeAttributes.Public, typeof(object), null);
var method = type.DefineMethod("###Start_v1.4.3.0", MethodAttributes.Public | MethodAttributes.HideBySig);
method.SetReturnType(typeof(void));
var generator = method.GetILGenerator();
generator.Emit(OpCodes.Nop);
generator.Emit(OpCodes.Ret);
type.CreateType();
assemblyBuilder.Save(@"test.dll");
如您所见,有一个名为 Entry
的 class 和一个名为 ###Start_v1.4.3.0
的方法。
我们现在已经使用它超过 7 年了,但每次我们都需要更改任何东西,这很痛苦,因为我们需要使用那些 Emits
,而且这不是微不足道的。
如果我们可以让 Roslyn 编译代码就好了:
public class Entry
{
public void ###Start_v1.4.3.0()
{
}
}
但由于方法名无效,所以无法正常工作
已编译的 dll 被第三方组件使用,它会查找此 class 和要执行的方法名称。我们试图联系开发人员以获得新版本,但没有成功。
我认为 Roslyn 根本不会编译它,但我相信以后可能会有一种方法可以将方法名称从 Start()
重命名为 ###Start_v1.4.3.0()
...我只是不知道该怎么做。
非常欢迎任何帮助。
如果唯一的问题是非法方法名称,您可以轻松解决该问题。
用合法的名字编译dll,然后你有几种方法可以改变方法名。
使用 mono.cecil
非常简单。
public void ChangeMethodName()
{
//Before changing the method name
var assem = Assembly.LoadFile(@"C:\temp\ClassLibrary1.dll");
Console.WriteLine(
assem.GetType("ClassLibrary1.Class1").
GetMethod("Start", BindingFlags.Static | BindingFlags.Public).
Invoke(null, null));
// Change the name
var module = ModuleDefinition.ReadModule(@"C:\temp\ClassLibrary1.dll");
TypeDefinition myType =
module.Types.First(type => type.Name == "Class1");
var method = myType.Methods.First(m => m.Name == "Start");
method.Name = "###Start_v1.4.3.0";
module.Write(@"C:\temp\ClassLibrary1_new.dll");
//After changing the method name
assem = Assembly.LoadFile(@"C:\temp\ClassLibrary1_new.dll");
Console.WriteLine(
assem.GetType("ClassLibrary1.Class1").
GetMethod("###Start_v1.4.3.0",
BindingFlags.Static|BindingFlags.Public).
Invoke(null, null));
}
public class Class1
{
public static string Start()
{
return $"my name is {MethodBase.GetCurrentMethod().Name}";
}
}
我需要将使用 Reflection.Emit 的现有代码转换为 Roslyn。
我目前的代码基本是这样的:
var assemblyName = new AssemblyName("AssemblyName");
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
var builder = assemblyBuilder.DefineDynamicModule("test", "test.dll");
var type = builder.DefineType("Entry", TypeAttributes.Public, typeof(object), null);
var method = type.DefineMethod("###Start_v1.4.3.0", MethodAttributes.Public | MethodAttributes.HideBySig);
method.SetReturnType(typeof(void));
var generator = method.GetILGenerator();
generator.Emit(OpCodes.Nop);
generator.Emit(OpCodes.Ret);
type.CreateType();
assemblyBuilder.Save(@"test.dll");
如您所见,有一个名为 Entry
的 class 和一个名为 ###Start_v1.4.3.0
的方法。
我们现在已经使用它超过 7 年了,但每次我们都需要更改任何东西,这很痛苦,因为我们需要使用那些 Emits
,而且这不是微不足道的。
如果我们可以让 Roslyn 编译代码就好了:
public class Entry
{
public void ###Start_v1.4.3.0()
{
}
}
但由于方法名无效,所以无法正常工作
已编译的 dll 被第三方组件使用,它会查找此 class 和要执行的方法名称。我们试图联系开发人员以获得新版本,但没有成功。
我认为 Roslyn 根本不会编译它,但我相信以后可能会有一种方法可以将方法名称从 Start()
重命名为 ###Start_v1.4.3.0()
...我只是不知道该怎么做。
非常欢迎任何帮助。
如果唯一的问题是非法方法名称,您可以轻松解决该问题。
用合法的名字编译dll,然后你有几种方法可以改变方法名。
使用 mono.cecil
非常简单。
public void ChangeMethodName()
{
//Before changing the method name
var assem = Assembly.LoadFile(@"C:\temp\ClassLibrary1.dll");
Console.WriteLine(
assem.GetType("ClassLibrary1.Class1").
GetMethod("Start", BindingFlags.Static | BindingFlags.Public).
Invoke(null, null));
// Change the name
var module = ModuleDefinition.ReadModule(@"C:\temp\ClassLibrary1.dll");
TypeDefinition myType =
module.Types.First(type => type.Name == "Class1");
var method = myType.Methods.First(m => m.Name == "Start");
method.Name = "###Start_v1.4.3.0";
module.Write(@"C:\temp\ClassLibrary1_new.dll");
//After changing the method name
assem = Assembly.LoadFile(@"C:\temp\ClassLibrary1_new.dll");
Console.WriteLine(
assem.GetType("ClassLibrary1.Class1").
GetMethod("###Start_v1.4.3.0",
BindingFlags.Static|BindingFlags.Public).
Invoke(null, null));
}
public class Class1
{
public static string Start()
{
return $"my name is {MethodBase.GetCurrentMethod().Name}";
}
}