【问题标题】:Implicitly creating an instance of a class that is located in a dependent dll隐式创建位于依赖 dll 中的类的实例
【发布时间】:2015-05-05 20:28:36
【问题描述】:

假设您正在开发一个名为"ThirdParty.dll" 的第三方DLL,它有一个名为JustTryToInstantiateMe 的类。假设您的客户有一个引用了"ThirdParty.dll" 的EXE,或者该EXE 没有引用"ThirdParty.dll",但如果以某种方式请求,该EXE 可以在PATH 中找到"ThirdParty.dll"。您无法控制 EXE,因为您是 "Thirdparty.dll" 的供应商,您只能修改 DLL 的功能。您的客户,即编写 EXE 的人,同意引用您的 DLL 或将您的 DLL 放在 PATH 中。仅此而已。

有没有办法在运行 EXE 时实例化 JustTryToInstantiateMe 而无需显式使用 new 或调用静态/共享方法/字段/属性?

也许只是以某种方式使用静态/共享构造函数?也许在AssemblyLoad() 事件上?也许使用注册表?启动过程?寻找想法...

【问题讨论】:

  • 你考虑过Activator.CreateInstance吗?
  • 如果 Justtrytoinstantiate me 是一个静态类,当您尝试使用该类时,将自动调用私有静态构造函数。您所需要的只是代码文件中的 using 语句(C#)。 using ThirdParty;
  • 这两个建议都假定 EXE 知道“JustTryToInstantiateMe”。正如问题中所述,情况并非如此。如果 clr 以某种方式指示 EXE 查找“ThirdParty.dll”,但 EXE 中没有直接引用“JustTryToInstantiateMe”的代码,则 EXE 可以在 PATH 中找到“ThirdParty.dll”
  • @RadioSpace - 你确定最后一部分是真的吗?在不确定的情况下,我想编译器会足够聪明,知道该类型实际上并没有被使用,因此不会调用静态构造函数。只是好奇。
  • 你怎么知道你想实例化什么类?你至少有“JustTryToInstantiateMe”作为字符串吗?您可以枚举程序集中的所有类型并使用反射创建实例:msdn.microsoft.com/en-us/library/…

标签: c# .net vb.net


【解决方案1】:

我知道的最接近的方法是动态加载程序集,然后从您创建的类的实例中调用方法。

这是代码的 c# 模板:

        //add using for system.reflection
        String className = "[NAME OF CLASS WITH FULL NAMESPACE GOES HERE]";
        String methodName = "[METHOD NAME GOES HERE]"
        String dllPath = "[FILE PATH FOR DLL GOES HERE]";

        Assembly assembly = Assembly.LoadFile(dllPath);
        Type type = assembly.GetType(className);
        MethodInfo method = type.GetMethod(methodName);
        object context = Activator.CreateInstance(type);

        //optionally set up parameters here
        object[] parameters = new object[0];
        String result = (String) method.Invoke(context, parameters);

例如,我可以创建一个这样的类(我知道,它是 VB,但后面是 C#。

        Public Class my_class
            Private hello = "hello world"
            Public Function gethello()
                Return hello
            End Function
        End Class

然后在编译之后,我可以在 C# 中使用以下代码来做我认为你在问的事情:

        //using system.reflection
        String className = "mytestlibrary.my_class";
        String dllPath = "...mytestlibrary.dll";
        String methodName = "gethello";
        Assembly assembly = Assembly.LoadFile(dllPath);
        Type type = assembly.GetType(className);
        MethodInfo method = type.GetMethod(methodName);
        object context = Activator.CreateInstance(type);
        object[] parameters = new object[0];
        String result = (String) method.Invoke(context, parameters);
        //result is "hello world"

现在,如果您想执行相同的操作,但使用已编译的 EXE 文件,那么代码几乎没有什么不同,但您需要创建一个桌面/控制台应用程序来封装其他可执行文件并正确命名您的 DLL。因此,在您的应用程序中,添加以下代码以从 EXE 中引用的 DLL 中获取类的实例。

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        String className = "My_Class";
        String ExePath = "[PATH TO EXE]";
        String methodName = "gethello";
        Assembly assembly = Assembly.LoadFile(ExePath);
        Type type = assembly.GetType(className);
        MethodInfo method = type.GetMethod(methodName);
        object context = Activator.CreateInstance(type);
        object[] parameters = new object[0];
        String result = (String) method.Invoke(context, parameters);

您也可以将程序集动态加载到 EXE 中,但这有点棘手,所以我将暂时保留它,除非您确实需要将 DLL 动态加载到 EXE 中。

【讨论】:

  • 这种反射方法是有意义的,但您需要将它放在 EXE 中。这是不允许的。您不能修改 EXE,您只能修改进入 DLL 的代码。
  • 啊,我弄反了。我将进行测试,看看结果如何。
  • @Denis,您实际上可以将程序集添加到已编译的可执行文件中,并使用这些新程序集来修改程序的执行方式。您无法更改代码,但在某种程度上您可以覆盖它。
  • 顺便说一句,自我上次编辑以来有任何反馈吗?如果给我同样的挑战,上面的代码就是我的处理方式。
  • 如果我能提供更多帮助,请告诉我。我将更新我对规范的回答。 -干杯:)
【解决方案2】:

通过研究,我发现这个问题的简单答案是这是不可能的。简短的回答是,为了加载 DLL 中的类,该类需要被某些东西引用。如果一个 DLL 能够通过仅仅位于 PATH 中而自行加载,这将带来各种安全问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-23
    • 1970-01-01
    • 2014-11-17
    • 1970-01-01
    • 2017-12-26
    相关资源
    最近更新 更多