使用Roslyn创建部分类 - 一个在运行时编译的类

时间:2015-09-27 09:51:58

标签: c# dynamic roslyn c#-6.0

我有一个班级(HelloWorld.cs):

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

}

上述类属性 BuildAction = Compile

我在另一个文件中有另一个类(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 = None和复制到输出目录=复制如果更新

现在的主要方法: 它使用Roslyn。

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."}

                }
            }

是否可以使用roslyn为常规的部分类提供与现有类相同的效果,其中一个类在构建期间编译,另一个类在运行时在相同的程序集中编译

3 个答案:

答案 0 :(得分: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));

这应该有效。

答案 1 :(得分:1)

不,如this answer所示,部分课程是纯粹的语言功能&#34;。在CLR级别,只有一个类。由于罗斯林最终只会发出一个集会,你不能修改&#34;你的班级就是这样。

答案 2 :(得分:0)

事实上,没有像部分类这样的想法。真正的语言功能是部分类定义

正如您在the documentation上看到的那样:

  

可以在两个或多个源文件上拆分类或结构,接口或方法的定义。每个源文件都包含类型或方法定义的一部分,并且在编译应用程序时将所有部分组合在一起。