2015-09-27 42 views
2

我有一個類(HelloWorld.cs):使用羅斯林創建部分類 - 一個編譯在運行時

public partial class HelloWorld 
{ 
    public void SayHello() 
    { 
     var message = "Hello, World!"; 
     var length = message.Length; 
     Console.WriteLine("{1} {0}", message, length); 
    } 

} 

上述類的屬性BuildAction的=編譯

我有另一個類在一個單獨的文件(HelloWorldExtend.cs):

public partial class HelloWorld 
    { 
     public void SayHelloExtend() 
     { 
      var message = "Hello, World Extended!"; 
      var length = message.Length; 
      Console.WriteLine("{1} {0}", message, length); 
     } 

    } 

但類的屬性是:BuildAction的=無和複製到輸出目錄=複製如果較新的

現在主要的方法: 其使用羅斯林。

static void Main(string[] args) 
     { 
      var code = File.ReadAllText("HelloWorldExtend.cs"); 
      var tree = SyntaxFactory.ParseSyntaxTree(code); 

      var compilation = CreateCompilation(tree); 
      var model = compilation.GetSemanticModel(tree);    

      ExecuteCode(compilation); 

      Console.ReadLine(); 

     } 

    private static void ExecuteCode(CSharpCompilation compilation) 
      { 
       using (var stream = new MemoryStream()) 
       { 
        compilation.Emit(stream); 

        var assembly = Assembly.Load(stream.GetBuffer()); 
        var type = assembly.GetType("HelloWorld"); 
        var greeter = Activator.CreateInstance(type); 

        var methodextend = type.GetMethod("SayHelloExtend"); 
        methodextend.Invoke(HelloWorld, null); 
        //Works perfect 

        var method = type.GetMethod("SayHello"); 
        method.Invoke(greeter, null); 

//method is returned null and gives an error : {"Object reference 
not set to an instance of an object."} 

       } 
      } 

IS有可能使用羅斯林,得到作爲常規局部類相同的效果,其中一個類被構建期間編譯和另一個是在運行時在相同組件編譯現有的類。

回答

3

簡短的回答:

原裝配已經編制。爲HelloWorld類定義已經被轉換爲IL和在編譯時,沒有額外的源文件,以彌補部分類的其它部分。

您可以創建一個新的程序集,其中包含自己版本的HelloWorld,它將部分文件的兩個部分作爲源提供。

然而

它看起來像你可以簡單地延長原班和可選使當前編譯的類的抽象類。

public abstract class HelloWorldBase 
{ 
    public void SayHello() 
    { 
     var message = "Hello, World!"; 
     var length = message.Length; 
     Console.WriteLine("{1} {0}", message, length); 
    } 
} 

設置上面類物業BuildAction = Compile

public class HelloWorld : HelloWorldBase 
{ 
    public void SayHelloExtend() 
    { 
     var message = "Hello, World Extended!"; 
     var length = message.Length; 
     Console.WriteLine("{1} {0}", message, length); 
    } 
} 

確保as part of your compilation, you reference the assembly containing HelloWorldBase before actually compiling the sources

compilation.AddReferences(new MetadataFileReference(typeof(HelloWorldBase).Assembly.location)); 

這應該工作。

+0

不,它不工作。它給出了錯誤:類型System.BadImageFormatException'的未處理的異常出現在mscorlib.dll 其他信息:無法加載文件或程序集「從MyRoslynProject加載0字節,版本= 1.0.0.0,文化=中性公鑰= null「或它的一個依賴關係。試圖加載格式不正確的程序。 – Satyajit

+1

@Satyajit什麼時候你會得到那個異常? 你需要認識到,在傑西的例子中,第二代碼片段需要具有其中包含了'HelloWorldBase'類型的程序集的引用,否則將無法正確編譯。 (並確保你從'HelloWorldBase'派生,而不是'helloWorldBase';))。 – Ties

+0

謝謝。我會檢查裝配的東西。它給出了錯誤:var assembly = Assembly.Load(stream.GetBuffer());但是,那麼如何讓原始程序集包含在這部分代碼中。 – Satyajit

1

沒有,如this answer指出,部分類是一個「純粹的語言特性」。在CLR層面上,只有一個類。由於Roslyn最終只會發佈一個程序集,所以你不能像這樣「修改」你的類。

0

事實上,不存在這樣的想作爲部分類。真正的語言功能是部分類定義

正如你可以看到the documentation

有可能分裂類或結構,接口或通過兩個或多個源文件的方法的定義。每個源文件都包含類型或方法定義的一部分,並且在編譯應用程序時組合所有部分。