0

I've set up a simple console application

In Program.cs I'm trying to get script to compile while inheriting a base class

using Microsoft.CSharp;
using System;
using System.CodeDom.Compiler;
using System.Data;

namespace TestingInConsole
{
    public class BaseClass { }

    class Program
    {
        static void Main(string[] args)
        {
            var scriptText = @"
                namespace TestingInConsole
                {
                    public class Test : BaseClass
                    {
                    }
                }";

            var compileOptions = new CompilerParameters();
            compileOptions.GenerateInMemory = true;

            var compiler = new CSharpCodeProvider();
            var compileResult = compiler.CompileAssemblyFromSource(compileOptions, scriptText);

            if (compileResult.Errors.Count > 0)
                throw new Exception($"Error in script: {compileResult.Errors[0].ErrorText}\nLine: {compileResult.Errors[0].Line}");

            var assembly = compileResult.CompiledAssembly;
            dynamic script = assembly.CreateInstance($"TestingInConsole.Test");

            // TODO: add Run() function to Test class
            DataSet dataSetResult = script.Run();

        }
    }
}

But I get the error

System.Exception: 'Error in script: The type or namespace name 'BaseClass' could not be found (are you missing a using directive or an assembly reference?) Line: 4'

after line: if (compileResult.Errors.Count > 0)

Questions

Is it possible for CSharpCodeProvider scripts like this to inherit base classes?

Or should I create new function in Program.cs to check if the script instance has proper functions (that I would in other case put in the base class)?

EDIT 1: Suggestions from comments

I've created new library project in my solution, added empty public class BaseClass to it, added a reference to it in Program.cs.

enter image description here

And this is what I've changed in Program.cs

        var compileOptions = new CompilerParameters();
        var assembliesPath = AppDomain.CurrentDomain.BaseDirectory;
        compileOptions.ReferencedAssemblies.Add(assembliesPath + "TestLibrary.dll");
        compileOptions.GenerateInMemory = true;

I've rebuilt both projects, but I still get the same error.

Dai
  • 141,631
  • 28
  • 261
  • 374
Monset
  • 648
  • 5
  • 25
  • Yes, but you haven't provided the base class to the compiler. Literally the only code that compiles is what is defined in the string literal scriptText. BaseClass isn't provided in that literal. – garty Jan 06 '20 at 13:51
  • How can I provide it the base class? (I'm new to this JIT thing) – Monset Jan 06 '20 at 13:52
  • Add the base class to the string "scriptText". What you're doing here is the same as clicking "File > New Project" creating a new console app and compiling. The code that is passed to that project is whatever is inside of the variable "scriptText". Nothing else. – garty Jan 06 '20 at 13:53
  • 1
    I think MS has some help pages about dynamically loading assemblies into another -- that should show you how to do it. You will need a using statement I expect. – Hogan Jan 06 '20 at 13:57
  • @garty Well, I would need the base class to be inside the project, as it would have functions and properties, and I would have multiple scripts that would all inherit this base class, and I would call scripts from the project, knowing that they have functions and properties from the `BaseClass`. The way you described it is that I would need to copy-paste `BaseClass` to each script, which defies the purpose of inheritance here. – Monset Jan 06 '20 at 14:00
  • 2
    Then what @Hogan said. Add the base scripts to a new class library, and add the class library as a reference when executing the script. https://learn.microsoft.com/en-us/dotnet/api/system.codedom.compiler.compilerparameters.referencedassemblies?view=netframework-4.8 – garty Jan 06 '20 at 14:02
  • 2
    This is not "JIT", JIT is what the runtime does when it turns your IL bytecode into CPU instructions. – CodeCaster Jan 06 '20 at 14:15
  • 2
    You have to do the same thing you'd do in an IDE project, add an entry to the References node. [Like this](https://learn.microsoft.com/en-us/dotnet/api/system.codedom.compiler.compilerparameters.referencedassemblies?view=netframework-4.8). Yes, adding a reference to your own .exe file is just fine. – Hans Passant Jan 06 '20 at 14:17
  • I've tried adding reference, but I still get the same error. Please check EDIT 1 in the question. Maybe I added this reference wrong somehow? – Monset Jan 06 '20 at 14:54
  • 1
    I'll emphasize again that creating a DLL is not necessary. But now that you did, we can no longer see whether the DLL is present in the correct directory (msbuild no longer helps) and whether you used the correct namespace name. If the error is exactly the same then it is probably the namespace name. – Hans Passant Jan 06 '20 at 14:59
  • 1
    I forgot to add `using TestLibrary;` at the top of my script. Now it works. I wouldn't be adding the reference to .exe because I'm just testing in this console application. This is what I'll be implementing in web application, but It is good to know. Thank you @HansPassant and @Hogan . – Monset Jan 06 '20 at 15:05

1 Answers1

0

Solution is the "EDIT 1: Suggestions from comments" in my question combined with my last comment "I forgot to add 'using TestLibrary;' at the top of my script.", that would look like this

        var scriptText = @"
            using TestLibrary; // <- this line here
            namespace TestingInConsole
            {
                public class Test : BaseClass
                {
                }
            }";
Monset
  • 648
  • 5
  • 25