Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/265.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在运行时列出、加载和实例化App_代码中的未知类_C# - Fatal编程技术网

C# 在运行时列出、加载和实例化App_代码中的未知类

C# 在运行时列出、加载和实例化App_代码中的未知类,c#,C#,我想在运行时加载并实例化位于我的App_代码文件夹中的类 这些类实现了IModule: public interface IModule { String Test(); } 测试类: // ~/App_Code/Test.cs namespace ModuleManagementSystem { class Test : IModule { public String Test() { return "Test

我想在运行时加载并实例化位于我的App_代码文件夹中的类

这些类实现了IModule:

public interface IModule
{
    String Test();
}
测试类:

// ~/App_Code/Test.cs

namespace ModuleManagementSystem
{
    class Test : IModule
    {
        public String Test()
        {
            return "Testing! One, two, thee!";
        }
    }
}
类文件由系统用户上传并作为模块

模块的类名将始终与模块文件名相同。


我正在寻找功能示例代码

我会尽快悬赏。


更新:

namespace ModuleManagementSystem
{
    public sealed class Compile
    {
        public void ToDLL(String sourcefile, String outputfile)
        {
            var compilerResults =
            CodeDomProvider.CreateProvider("CSharp").CompileAssemblyFromFile(
                new CompilerParameters {
                    OutputAssembly = outputfile,
                    GenerateInMemory = false,
                    TreatWarningsAsErrors = false,
                    GenerateExecutable = false,
                },
                sourcefile
            );
        }
    }
}
上述工程适用于:

// ~/App_Code/Test.cs

public class Test
{
    // ...
}
但是如果我实现我的
IModule
接口:

namespace ModuleManagementSystem
{
    public interface IModule
    {
        String HelloWorld();
    }
}
我得到以下错误:

{c:\inetpub\wwwroot\ModuleManagementSystemWeb\App\u Code\Test.cs(4,21) :错误CS0246:类型或命名空间 无法指定名称“ModuleManagementSystem” 找不到(您是否缺少一个用户 指令或程序集 参考?}System.CodeDom.Compiler.CompilerError

IModule
接口和
Compile
类都位于同一类库中,该类库从web应用程序中引用:


我觉得实际上传到应用程序代码文件夹是个坏主意。我会使用一个单独的文件夹,ASP.NET对此一无所知。这样,您就不会让框架试图为您自动编译代码

您可以轻松地使用-查看示例来编译和运行代码

不过,我希望这只是供内部使用(并且经过验证)——我不建议让不受信任的用户在您的web服务器上执行他们的代码。您可以通过运行代码使其稍微安全一点,这大大减少了权限,但您仍然有代码紧循环等风险

编辑:为了回答更新后的问题,您只需要提供适当的程序集供参考,其中包含
IModule
。请参阅
CompilerParameters.ReferencedAssembles
属性

Assembly assembly = Assembly.Load(assemblyName);

IModule instance = assembly.CreateInstance(typeName) as IModule;

您还可以使用该方法创建实例,而无需显式引用程序集。

您可以使用反射进行创建,下面是一个非常简单的方法,它将返回传递给函数的模块名[类名]的实例

Public Shared Function GetDALInstance(ByVal moduleClassName As String) As IModule
        Dim className As String
        dim path as string = <<NamespacePath>>  
        className = Path + moduleClassName
        Return Assembly.Load(Path).CreateInstance(className)
    End Function
公共共享函数GetDaInstance(ByVal moduleClassName作为字符串)作为IModule
将类名设置为字符串
作为字符串的dim路径=
className=路径+模块className
返回Assembly.Load(Path).CreateInstance(className)
端函数

上面的方法在vb.net中,您可以简单地将其转换为c#

我决定在运行时加载的类必须实现给定的接口,并且类的名称必须与文件名相同

类上载和编译到的文件夹是不相关的。


加载已编译类(.dll)并实例化它:

return (IInterfaceClassesMustImplement)Assembly
/* continued --> */ .LoadFile("c:\...\SomeClass.dll")
/* continued --> */ .CreateInstance("SomeClass");
internal static class Compiler
{
    internal static void AssemblyFromFile(
        String classFilePath,
        String assemblyFilePath,
        String[] referencedAssemblies
    )
    {
        var cp = new CompilerParameters { OutputAssembly = assemblyFilePath };

        foreach (String ra in referencedAssemblies)
        {
            cp.ReferencedAssemblies.Add(ra);
        }

        CompilerResults cr = CodeDomProvider.CreateProvider("CSharp")
        /* continued --> */ .CompileAssemblyFromFile(cp, classFilePath);

        if (cr.Errors.Count > 0) // throw new Exception();
    }
}
编译一个类:

return (IInterfaceClassesMustImplement)Assembly
/* continued --> */ .LoadFile("c:\...\SomeClass.dll")
/* continued --> */ .CreateInstance("SomeClass");
internal static class Compiler
{
    internal static void AssemblyFromFile(
        String classFilePath,
        String assemblyFilePath,
        String[] referencedAssemblies
    )
    {
        var cp = new CompilerParameters { OutputAssembly = assemblyFilePath };

        foreach (String ra in referencedAssemblies)
        {
            cp.ReferencedAssemblies.Add(ra);
        }

        CompilerResults cr = CodeDomProvider.CreateProvider("CSharp")
        /* continued --> */ .CompileAssemblyFromFile(cp, classFilePath);

        if (cr.Errors.Count > 0) // throw new Exception();
    }
}

Jon,ASP.NET提供了声明您自己的生成文件夹的功能。:)不需要手动编译,但我想拥有更多的控制权。特别是,我不希望每次上传新文件时都重新启动应用程序。我还想确保新代码只能访问我想让它知道的应用程序部分。如果是这样的话,是的。这样会更好。我还建议添加一些CAS属性,这些属性明确拒绝访问除真正需要的权限之外的所有权限。@Jon Skeet。更新了我的问题。介意再看一眼吗?:)嗨,丹尼尔。谢谢你的回答。不过,我在名为“Mediator.CreateInstance()”的C#框架中找不到任何内容。你能详细解释一下吗?我写的是Mediator.CreateInstance(),但意思是Activator.CreateInstance()。参考MSDN。组装。负载(“测试”);导致了我这方面的错误。什么例外?安全例外?找不到程序集?“Test”真的是程序集的名称还是仅仅是文件名?我尝试了以下方法:assembly.Load(“Test.cs”)、assembly.Load(MapPath(“~/App\u Code/”)+“Test.cs”),这两种方法都导致找不到程序集