【问题标题】:Invoking an Interface method using reflection使用反射调用接口方法
【发布时间】:2020-05-15 12:25:22
【问题描述】:

我正在使用反射来调用接口方法,并且出现此错误消息“对象引用未设置为对象的实例。”我也尝试使用 ConstructorInfo 并且也有错误。请帮忙。

public class ClassA 
{ 
       private void MethodA(int num, ClassC result)
       {
       } 
}
public interface InterfaceB 
{ 
       ClassC MethodB(int num); 
}
internal class ClassB 
{ 
      public ClassC MethodB(int num)
      {
      } 
}

Type typClassA = Type.GetType("ClassA");
Type typInterfaceB = Type.GetType("InterfaceB");
MethodInfo methodB = typInterfaceB.GetMethod("MethodB", BindingFlags.Public | BindingFlags.Instance); // Error lies here
ClassC result = (ClassC) methodB.Invoke(typInterfaceB, new object[]{num});

MethodInfo methodA = typClassA.GetMethod("MethodA", BindingFlags.NonPublic | BindingFlags.Instance);
methodA.Invoke(typClassA, new object[]{num, result});

ClassB 的实际代码并未声明为“public ClassB : InterfaceB”,而是包含更多类,并且 ClassB 是内部访问。请参阅已编辑的代码。很抱歉多次更改代码,因为我不知道如何简化这种情况。

【问题讨论】:

  • 你使用什么编程语言?
  • 你为什么要尝试获取Static 方法?你能提供更多的代码吗?
  • C#,其实我用的是Instance。抱歉,我没有改回来。
  • 完全不清楚。你有实现 InterfaceB.MethodB 的类的实例吗?
  • 是否可以发布一些实际编译的代码?我无法理解您在这里的意图,这意味着我无法真正尝试回答这个问题。首先,您可以在类中添加“类”声明,并为所有方法填写返回类型...

标签: c# reflection


【解决方案1】:

您必须为 class 提供完全限定的名称。请注意以下示例

namespace ConsoleApplication10
{
    interface IA
    {
        void Print();
    }

    class A : IA
    {
        public void Print()
        {
            Console.WriteLine("Hello");
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            Type type = Type.GetType("ConsoleApplication10.A");
            type.GetMethod("Print").Invoke(Activator.CreateInstance(type, null), null);
        }
    }
}

【讨论】:

    【解决方案2】:

    C#使用duck-typing。 因此,为了实际实现接口方法,您必须声明您的类实现了该接口:

    public class ClassB : InterfaceB
    

    您的代码中还有其他问题:

    Type typInterfaceB = Type.GetType("InterfaceB"); // unless you have no namespace at all, you need to specify the fully qualified name
    
    // Probably you got an NRE because of above issue here
    MethodInfo methodB = typInterfaceB.GetMethod("MethodB", BindingFlags.Public | BindingFlags.Instance); 
    
    // this does not work, because the first argument needs to be an instance 
    // try "new ClassB()" instead
    ClassC result = (ClassC) methodB.Invoke(typInterfaceB, new object[]{num});
    

    【讨论】:

    • 实际代码不是公共类 ClassB : InterfaceB。这很复杂。
    【解决方案3】:

    我不太明白你想要什么,但我认为你需要这样的东西

    public interface InterfaceB 
    {
        int method(int d);
    }
    public class ClassB:InterfaceB
    {
        int a = 10;
        public int method(int d)
        {
            return a + d;
        }
    }
    
    
    var b = new ClassB();
    var mi = typeof(ClassB).GetInterface("InterfaceB").GetMethod("method");
    var res = mi.Invoke(b, new object[] { 10 }); // res == 20
    

    更新
    又一个变种

    public interface InterfaceB 
    {
        int method(int d);
    }
    public class ClassB:InterfaceB
    {
        int a = 10;
        public int method(int d)
        {
            return a + d;
        }
    }
    
    
    var b = new ClassB();
    var mi = typeof(InterfaceB).GetMethod("method");
    var res = mi.Invoke(b, new object[] { 10 }); // res == 20
    

    【讨论】:

      【解决方案4】:

      您正试图在 System.Type 类型的对象上调用方法,而不是在实现该接口的对象上。

      MethodInfo.Invoke 的第一个参数是您要在其上调用方法的对象的实例...您使用的是System.Type 对象的实例,而不是ClassAClassB 中的一个实例

      【讨论】:

        【解决方案5】:

        你所有的方法都是instance(不是static)方法,所以你必须创建实例来调用它们,并传递这些instancesInvoke,例如:

          // Let's call MethodA from ClassA
        
          Object instanceA = new ClassA();
          MethodInfo methodA = instanceA.GetType().GetMethod("MethodA", BindingFlags.NonPublic | BindingFlags.Instance);
        
          // Pay attention to 1st argument - instanceA
          methodA.Invoke(instanceA, new object[]{num, result});  
        
          ...
        
          // Since ClassB doesn't implement InterfaceB, the only option 
          // is to call MethodB of ClassB
          Object instanceB = new ClassB();
          MethodInfo methodB = instanceB.GetType().GetMethod("MethodB", BindingFlags.Public | BindingFlags.Instance);
        
          ClassC result = (ClassC) (methodB.Invoke(instanceB, new object[]{num}));
        

        【讨论】:

          【解决方案6】:

          如果你确定你的对象有需要的方法,那么你可以使用dynamic 并这样写:

          var result = (yourObject as dynamic).YourMethod("SomeParam");
          

          【讨论】:

            【解决方案7】:
            interface IGetNames
            {
                string GetFirstName();
                string GetMiddleName();
            }
            public class GetNames : IGetNames
            {
                public string GetFirstName()
                {
                    return "First Name";
                }
                public string GetMiddleName()
                {
                    return "Middle Name";
                }
            }
             static void Main(string[] args)
            {
            Type _Interface = Type.GetType("ConsoleApplication2.IGetNames");
            Type _Class = Type.GetType("ConsoleApplication2.GetNames");
            InterfaceMapping GetInterfaceMap = _Class.GetInterfaceMap(_Interface);
            MethodInfo methodInfo =  GetInterfaceMap.TargetMethods[0];
            object str =  methodInfo.Invoke(Activator.CreateInstance(GetInterfaceMap.TargetType), null);
            }
            

            【讨论】:

            • 为您的代码提供额外的解释会很有用,这样开发人员可以理解您的推理。这对于可能不熟悉语法的新开发人员尤其重要。此外,它可以帮助减少对后续问题的需求。您介意用更多详细信息更新您的评论吗?
            猜你喜欢
            • 2012-11-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-09-21
            相关资源
            最近更新 更多