2

I have a class (HelloWorld.cs):

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

}

The above class the property BuildAction = Compile.

I have another class in a separate file (HelloWorldExtend.cs):

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

    }

But the properties of the class are: BuildAction = None and Copy to output directory = Copy if newer

Now the main method: Its using 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."}

                }
            }

IS it possible to use roslyn to give the same effect as a regular partial class to an existing class where one class is compiled during build and another is compiled at runtime in the same assembly.

svick
  • 236,525
  • 50
  • 385
  • 514
Satyajit
  • 1,971
  • 5
  • 28
  • 51

3 Answers3

3

Short answer: No.

The original assembly had already been compiled. The class definition for HelloWorld is already converted to IL and at compile time there was no additional source file to make up the other parts of the partial class.

You can create a new assembly containing its own version of HelloWorld by supplying it both parts of the partial file as source.

However

It looks like you may be able to simply extend the original class and optionally make the currently compiled class an abstract class.

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

Set above class the property BuildAction = Compile.

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

Make sure that as part of your compilation, you reference the assembly containing HelloWorldBase before actually compiling the sources:

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

That should work.

jessehouwing
  • 106,458
  • 22
  • 256
  • 341
  • No, its not working. It gives the error : An unhandled exception of type 'System.BadImageFormatException' occurred in mscorlib.dll Additional information: Could not load file or assembly '0 bytes loaded from MyRoslynProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. An attempt was made to load a program with an incorrect format. – Satyajit Sep 27 '15 at 10:12
  • 1
    @Satyajit When exactly do you get that exception? You do need to realize that in the example of Jesse the second code snippet needs to have a reference to the assembly which contains the `HelloWorldBase` type, otherwise it won't be able to compile correctly. (And make sure you derive from `HelloWorldBase`, and not `helloWorldBase` ;)). – Ties Sep 27 '15 at 10:41
  • Thanks. I will check the assembly stuff. It gives error at: var assembly = Assembly.Load(stream.GetBuffer()); But then, how do I get the original assembly to be included in this part of code. – Satyajit Sep 27 '15 at 11:27
  • Are you sure that the emitted assembly is actually valid? If the original compilation already had diagnostics (aka build errors), then the resulting assembly won't be emitted, and is probably not valid. Referencing the assembly which contains `HelloWorldBase` needs to happen somewhere in your `CreateCompilation` method. Depending on what you do there, probably you need to do something like `.AddMetadataReferences()` on the project, making a MetadataReference something like `MetadataReference.CreateFromFile(typeof(HelloWorldBase).Assembly.Location)`. – Ties Sep 27 '15 at 13:19
  • An example of this can be found [here](https://github.com/Vannevelj/RoslynTester/blob/master/RoslynTester/RoslynTester/Helpers/DiagnosticVerifier.cs#L429), for example. – Ties Sep 27 '15 at 13:19
  • 1
    Thanks. Will go through this. Looks like, I will be able to resolve the issue with this. – Satyajit Sep 27 '15 at 13:38
1

No, as indicated in this answer, partial classes are a "purely language feature". On the CLR level, there is only one class. Since Roslyn will eventually just emit an assembly, you cannot "amend" your class like that.

Community
  • 1
  • 1
Ties
  • 1,205
  • 2
  • 15
  • 28
0

In fact, there is no such think as partial classes. The real language feature is partial class definitions.

As you can see on the documentation:

It is possible to split the definition of a class or a struct, an interface or a method over two or more source files. Each source file contains a section of the type or method definition, and all parts are combined when the application is compiled.

Paulo Morgado
  • 14,111
  • 3
  • 31
  • 59