2016-06-28 47 views
2

我需要將使用Reflection.Emit的現有代碼轉換爲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了一個名爲###Start_v1.4.3.0方法類。

我們現在使用這個已經超過7年了,但是我們需要改變任何事情,這是一種痛苦,因爲我們需要使用那些Emits,這不是微不足道的。

這將是巨大的,如果我們可以只是羅斯林編譯代碼:

public class Entry 
{ 
    public void ###Start_v1.4.3.0() 
    { 
    } 
} 

但它不工作,由於該方法名稱爲無效。

編譯後的dll由第三方組件使用,它會查找要執行的類和方法名稱。我們試圖讓開發者有一個新的版本,但沒有運氣。

我認爲Roslyn不會編譯這個,但我相信可能有一種方法來重命名方法名稱,比如說我們只需要說Start()###Start_v1.4.3.0() ......我只是不知道該怎麼做。

任何幫助將非常受歡迎。

+0

我想你可以使用[反彙編](https://msdn.microsoft.com/en-us/library/f7dy01k1.aspx)和[ILASM(https://msdn.microsoft.com/ en-us/library/496e4ekx.aspx)或Cecil,以便在之後進行修補。 –

+0

也許你應該提出一個允許任意成員名稱的模式的功能請求。 CLR沒有這些名字的問題,我認爲Roslyn中的任何東西都不會因爲允許這樣做而突破。 – usr

回答

5

如果唯一的問題是非法的方法名稱,您可以輕鬆解決該問題。

使用合法名稱編譯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}"; 
    } 
}