C# 在 appdomain 调用方法中加载 dll,而不会再次加载 dll

Posted

技术标签:

【中文标题】C# 在 appdomain 调用方法中加载 dll,而不会再次加载 dll【英文标题】:C# load dll in appdomain recall methods wilhout loadding dll again 【发布时间】:2019-03-05 19:11:27 【问题描述】:

我有一个控制台应用程序在新的应用程序域中加载单个 dll,并且我能够调用该 dll 中的方法。我希望能够在不重新加载 dll 的情况下再次调用该方法。最好我希望能够加载多个 dll 并在卸载 appdomain 之前从其中的任何一个中调用一个方法。

using System;

using System.Reflection;

namespace Parent

    public interface ILoader
    
        int Execute(int arg1, int arg2);
    

    public class Loader : MarshalByRefObject, ILoader
    

        public int Execute(int arg1, int arg2)
        

            byte[] test1 = System.IO.File.ReadAllBytes("C:\\Users\\username\\source\\repos\\Test\\Test\\bin\\Debug\\Test.dll");

            Assembly test = Assembly.Load(test1);
            foreach (Type type in test.GetTypes())
            
                if (type.ToString().ToUpper() == "PROGRAM")
                

                    var o = Activator.CreateInstance(type);
                    Console.WriteLine("found Program");
                    MethodInfo method = type.GetMethod("math", new[]  typeof(int), typeof(int) );
                    var returnvalue = method.Invoke(o, new object[]  arg1, arg2 );


                    return (int)returnvalue;
                
                return 0;
            
            return 0;
        

    
    class Program
    
            static void Main(string[] args)
            
                int arg1 = Convert.ToInt32(args[0]);
                int arg2 = Convert.ToInt32(args[1]);
                Console.WriteLine(args[0], args[1]);
                var domain = AppDomain.CreateDomain("child");
                var loader = (ILoader)domain.CreateInstanceAndUnwrap(typeof(Loader).Assembly.FullName, typeof(Loader).FullName);
                Console.Out.WriteLine(loader.Execute(arg1, arg2));
            //reloads appdomain I dont want that
            Console.Out.WriteLine(loader.Execute(2, 3));
                Console.ReadKey();
                AppDomain.Unload(domain);
                Console.WriteLine("Appdomain unloaded");
                Console.ReadKey();

            
        
    

测试 DLL,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


    class Program
    
        public static int math(int arg1, int arg2)
        
            int a = arg1;
            int b = arg2;
            int c = a + b;
            return c;
        
    

【问题讨论】:

【参考方案1】:

main 函数之外将domain 变量声明为static 变量,因为您不能在函数内部声明static 变量。 static 变量在函数执行后不会删除其数据 - 这就是为什么它被称为“静态”,因为它永远不会改变,很像一个常量,而不是一个“动态”变量。

【讨论】:

谢谢,我想我把每个人都弄糊涂了,我的意思是,//在应用程序域中重新加载 dll,这正是代码的操作方式,我猜我真正需要做的是加载 dll 并解开在其中使用 createinstanceandunwrap 函数,但我发现 msdn 有点令人困惑,并且在任何地方都没有直接的示例。【参考方案2】:

想通了。如果它不存在,则必须创建第二个函数来加载二进制文件和 if 语句。对于那些关注应用程序域的人据我了解,接口是共享的函数,可让您调用加载到另一个应用程序域中的类。

using Parent;
using System;
using System.Reflection;

namespace Parent

    public interface ILoader
    

        int ExecuteAssm(int arg1, int arg2);
        byte[] Test();
    

    public class Loader : MarshalByRefObject, ILoader
    
        Assembly test1 = null;
        byte[] test;
        public byte[] Test()
        
            byte[] test = System.IO.File.ReadAllBytes("C:\\Users\\username\\source\\repos\\Test\\Test\\bin\\Debug\\Test.dll");
            return test;
        
        public int ExecuteAssm(int arg1, int arg2)
        

            if (test1 == null)
            
                test = Test();
                test1 = Assembly.Load(test);
            

            foreach (Type type in test1.GetTypes())

                if (type.ToString().ToUpper() == "PROGRAM")
                
                    MethodInfo method = type.GetMethod("math");
                    object o = test1.CreateInstance("math");
                    var returnint = method.Invoke(o, new object[]  arg1, arg2 );
                    Console.WriteLine(method);
                    Console.WriteLine(returnint);
                    return (int)returnint;
                
            return 0;
        
    
        //Type t = test1.GetType("Test.Class1");

        //var methodInfo = t.GetMethod("math", new Type[]  typeof(int), typeof(int) );
        //var o = Activator.CreateInstance(t);
        //var result = MethodInfo.(o, new Type[]  32, 32 );


    

class Program

    static void Main(string[] args)
    

        var domain = AppDomain.CreateDomain("child");
        var loader = (ILoader)domain.CreateInstanceAndUnwrap(typeof(Loader).Assembly.FullName, typeof(Loader).FullName);
        loader.ExecuteAssm(32, 32);
        loader.ExecuteAssm(2, 2);
        AppDomain.Unload(domain);
        // int returnint = ILoader.ExecuteAssm(32, 32);
        //Console.WriteLine(returnint);
    

【讨论】:

以上是关于C# 在 appdomain 调用方法中加载 dll,而不会再次加载 dll的主要内容,如果未能解决你的问题,请参考以下文章

在沙盒 Appdomain 中加载程序集 - SecurityException

无法在 appDomain 中加载程序集

在新的 appdomain 中加载 C 模块失败

AppDomain 详解二-C#中动态加载和卸载DLL

C# 防止 AppDomain 程序集的类实例访问文件

在 .NET 中,创建新的 AppDomain 时是不是调用静态构造函数?