C#“找不到”现有方法

发布于 2024-10-12 04:33:52 字数 2567 浏览 6 评论 0原文

问候! 我一直在(有点)闲逛 C# 及其程序集。因此,我发现了一个有趣的功能,例如动态加载程序集并调用其类成员。谷歌了一下,我在这里写了某种“程序集浏览器”。 (我使用了 此处此处这里并且没有一个给出任何预期的结果)。

但我发现了一个小错误:当我尝试从已加载的程序集中调用类方法时,应用程序引发了 MissingMethod 异常。我确信我正在加载的 DLL 包含我尝试调用的类和方法(我的应用程序确保我以及 RedGate 的 .NET Reflector 一样):

alt text

主要应用程序代码似乎没问题,我开始思考我的 DLL 是否有问题......啊,我已经将这两个项目放入一种解决方案,但我认为它不会造成任何麻烦。是的,DLL 项目具有“类库”目标,而主应用程序具有“控制台应用程序”目标。

所以,问题是:他们出了什么问题?

以下是一些源代码:

DLL 源:

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

namespace ClassLibrary1
{
    public class Class1
    {
        public void Main()
        {
            System.Console.WriteLine("Hello, World!");
        }
    }
}

主应用程序源:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Assembly asm = Assembly.LoadFrom(@"a\long\long\path\ClassLibrary1.dll");

            try
            {
                foreach (Type t in asm.GetTypes())
                {
                    if (t.IsClass == true && t.FullName.EndsWith(".Class1"))
                    {
                        object obj = Activator.CreateInstance(t);
                        object res = t.InvokeMember("Main", BindingFlags.Default | BindingFlags.InvokeMethod, null, obj, null); // Exception is risen from here
                    }
                }
            }
            catch (Exception e)
            {
                System.Console.WriteLine("Error: {0}", e.Message);
            }

            System.Console.ReadKey();
        }
    }
}

UPD: 适用于一种情况 - 当 DLL 方法不带参数时:

DLL 类(如果方法不是静态的也适用):

public class Class1
{
    public static void Main()
    {
        System.Console.WriteLine("Hello, World!");
    }
}

方法调用代码:

object res = t.InvokeMember("Main", BindingFlags.Default | BindingFlags.InvokeMethod, null, null, null);

Greetings!
I've been fooling around (a bit) with C# and its assemblies. And so i've found such an interesting feature as dynamic loading assemblies and invoking its class members. A bit of google and here i am, writing some kind of 'assembly explorer'. (i've used some portions of code from here, here and here and none of 'em gave any of expected results).

But i've found a small bug: when i tried to invoke class method from assembly i've loaded, application raised MissingMethod exception. I'm sure DLL i'm loading contains class and method i'm tryin' to invoke (my app ensures me as well as RedGate's .NET Reflector):

alt text

The main application code seems to be okay and i start thinking if i was wrong with my DLL... Ah, and i've put both of projects into one solution, but i don't think it may cause any troubles. And yes, DLL project has 'class library' target while the main application one has 'console applcation' target.

So, the question is: what's wrong with 'em?

Here are some source code:

DLL source:

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

namespace ClassLibrary1
{
    public class Class1
    {
        public void Main()
        {
            System.Console.WriteLine("Hello, World!");
        }
    }
}

Main application source:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Assembly asm = Assembly.LoadFrom(@"a\long\long\path\ClassLibrary1.dll");

            try
            {
                foreach (Type t in asm.GetTypes())
                {
                    if (t.IsClass == true && t.FullName.EndsWith(".Class1"))
                    {
                        object obj = Activator.CreateInstance(t);
                        object res = t.InvokeMember("Main", BindingFlags.Default | BindingFlags.InvokeMethod, null, obj, null); // Exception is risen from here
                    }
                }
            }
            catch (Exception e)
            {
                System.Console.WriteLine("Error: {0}", e.Message);
            }

            System.Console.ReadKey();
        }
    }
}

UPD: worked for one case - when DLL method takes no arguments:

DLL class (also works if method is not static):

public class Class1
{
    public static void Main()
    {
        System.Console.WriteLine("Hello, World!");
    }
}

Method invoke code:

object res = t.InvokeMember("Main", BindingFlags.Default | BindingFlags.InvokeMethod, null, null, null);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

月下伊人醉 2024-10-19 04:33:52

您可能会弄错 InvokeMember() 参数。下面是一个有效的示例:

using System;
using System.Reflection;

class Program {
    static void Main(string[] args) {
        if (args.Length > 0) Console.WriteLine(args[0]);
        else {
            Assembly asm = Assembly.LoadFrom(Assembly.GetEntryAssembly().Location);
            foreach (Type t in asm.GetTypes()) {
                if (t.IsClass == true && t.FullName.EndsWith(".Program")) {
                    //object obj = Activator.CreateInstance(t);
                    object res = t.InvokeMember("Main",
                        BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod,
                        null, null,
                        new object[] { new string[] { "Invoked" } });
                }
            }
        }
    }
}
  • 注意 Main() 方法如何不是公共的,因此 BindingFlags.NonPublic
  • 注意 Main() 方法如何是静态的,因此 BindingFlags.Static
  • 出于同样的原因,为 target< 传递 null /em> 参数
  • 出于同样的原因,CreateInstance 不是必需的。
  • 请注意 Main() 方法如何接受 string[] 参数,您必须传递它以获取 Reflection 来找到正确的方法重载。

对 Main() 方法遵循相同的逻辑:

                object res = t.InvokeMember("Main",
                    BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod,
                    null, obj,
                    new object[] { });

You are likely getting the InvokeMember() arguments wrong. Here's a sample that works:

using System;
using System.Reflection;

class Program {
    static void Main(string[] args) {
        if (args.Length > 0) Console.WriteLine(args[0]);
        else {
            Assembly asm = Assembly.LoadFrom(Assembly.GetEntryAssembly().Location);
            foreach (Type t in asm.GetTypes()) {
                if (t.IsClass == true && t.FullName.EndsWith(".Program")) {
                    //object obj = Activator.CreateInstance(t);
                    object res = t.InvokeMember("Main",
                        BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod,
                        null, null,
                        new object[] { new string[] { "Invoked" } });
                }
            }
        }
    }
}
  • Note how the Main() method isn't public, thus BindingFlags.NonPublic
  • Note how the Main() method is static, thus BindingFlags.Static
  • For the same reason, pass null for the target parameter
  • For the same reason, CreateInstance isn't necessary
  • Note how the Main() method takes a string[] argument, you have to pass it to get Reflection to find the correct method overload.

Follow the same logic for your Main() method:

                object res = t.InvokeMember("Main",
                    BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod,
                    null, obj,
                    new object[] { });
笑梦风尘 2024-10-19 04:33:52

为什么要创建一个实例(Activator.CreateInstance(t))来调用静态方法???它应该是:

t.InvokeMember(
     "Main", 
     BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, 
     null, 
     null, 
     new object[] { new string[0] }
);

此外,定义的这个方法不返回任何值,因此不需要为其分配返回变量。

为了消除所有误解,我在这里创建了一个完整的工作演示: http://www.mediafire.com /?n7h9b8ghomfv17d

Why are you craeting an instance (Activator.CreateInstance(t)) in order to invoke a static method???? It should be:

t.InvokeMember(
     "Main", 
     BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, 
     null, 
     null, 
     new object[] { new string[0] }
);

Also this method as defined doesn't return any value so no need to assign it a return variable.

And in order to clear all misunderstandings I've created a full working demo here: http://www.mediafire.com/?n7h9b8ghomfv17d

衣神在巴黎 2024-10-19 04:33:52

InvokeMember 的最后一个参数是包含该方法参数的对象数组。

您在那里传递 null ,您应该传递包含单个元素(字符串数组)的对象数组。

The last parameter to InvokeMember is an array of Objects containing the arguments to the method.

You're passing null there, you should be passing an array of objects containing a single element (an array of strings).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文