How to load a class from .cs file and use it in code

天大地大妈咪最大 提交于 2020-06-17 14:11:33

问题


I want to load a class form a .cs file and use it in another code.
Assume I have a .cs file which contains code like that:

//some imports

public class Commands
{

     //a lot of commands

}

What I am trying is to load this class from a file using CSharpCodeProvider or whatever and create a list of Commands.

A piece of code from a console app.

list<Commands> lst;

The question is how can I load Commands class dynamically (at runtime) (without restarting the console app or starting VS) and create the list of Commands?


回答1:


Try this example, which I have put together and tested:

Build program.cs as a .Net Framework Console App in e.g. Visual Studio.

// program.cs
using System;
using System.IO;
using System.CodeDom.Compiler;
using System.Reflection;

namespace RuntimeCompile
{
    class Program
    {
        static void Main(string[] args)
        {
            // Get a path to the file(s) to compile.
            FileInfo sourceFile = new FileInfo("mySource.cs");
            Console.WriteLine("Loading file: " + sourceFile.Exists);

            // Prepary a file path for the compiled library.
            string outputName = string.Format(@"{0}\{1}.dll",
                Environment.CurrentDirectory,
                Path.GetFileNameWithoutExtension(sourceFile.Name));

            // Compile the code as a dynamic-link library.
            bool success = Compile(sourceFile, new CompilerParameters()
            {
                GenerateExecutable = false, // compile as library (dll)
                OutputAssembly = outputName,
                GenerateInMemory = false, // as a physical file
            });

            if (success)
            {
                // Load the compiled library.
                Assembly assembly = Assembly.LoadFrom(outputName);

                // Now, since we didn't have reference to the library when building
                // the RuntimeCompile program, we can use reflection to create 
                // and use the dynamically created objects.
                Type commandType = assembly.GetType("Command");

                // Create an instance of the loaded class from its type information.
                object commandInstance = Activator.CreateInstance(commandType);

                // Invoke the method by name.
                MethodInfo sayHelloMethod = commandType.GetMethod("SayHello", BindingFlags.Public | BindingFlags.Instance);
                sayHelloMethod.Invoke(commandInstance, null); // no arguments, no return type
            }

            Console.WriteLine("Press any key to exit...");
            Console.Read();
        }

        private static bool Compile(FileInfo sourceFile, CompilerParameters options)
        {
            CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");

            CompilerResults results = provider.CompileAssemblyFromFile(options, sourceFile.FullName);

            if (results.Errors.Count > 0)
            {
                Console.WriteLine("Errors building {0} into {1}", sourceFile.Name, results.PathToAssembly);
                foreach (CompilerError error in results.Errors)
                {
                    Console.WriteLine("  {0}", error.ToString());
                    Console.WriteLine();
                }
                return false;
            }
            else
            {
                Console.WriteLine("Source {0} built into {1} successfully.", sourceFile.Name, results.PathToAssembly);
                return true;
            }
        }
    }
}

In the output directory (bin), next to the console app executable place a text file named mySource.cs with this content:

// mySource.cs
using System;

internal class Program
{
    static void Main()
    {
        Console.WriteLine("Hello from mySource!");
        Console.ReadLine();
    }
}

public class Command
{
    public void SayHello()
    {
        Console.WriteLine("Hello (Command)");
    }
}

Then run the first console app and observe it's output. It should log "Hello (Command)", showing that the code was correctly compiled, loaded and executed.

The example shows how to use the CodeDom.Compiler to compile a cs-file at runtime and then load it as dll to run code within it. Be aware, that almost no error handling was implemented.

This should answer the question, but there may still be better approaches to handling your use-case. In case of plugin loading it makes sense to use interfaces which are added as a reference to both assemblies to avoid the use of reflection, etc.




回答2:


There is probably a better way to achieve your overall goal, like dependency injection.

However, you can do it with the ICodeCompiler.

See this article https://support.microsoft.com/en-ca/help/304655/how-to-programmatically-compile-code-using-c-compiler




回答3:


To load the c# class from another c# class you need to use "using"

using Commands;
public class class1
{
    private list<Commands>lst;
    //...
}


来源:https://stackoverflow.com/questions/50708527/how-to-load-a-class-from-cs-file-and-use-it-in-code

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!