【问题标题】:Delegate to an instance method cannot have null 'this'委托给实例方法不能有 null 'this'
【发布时间】:2011-04-14 17:56:50
【问题描述】:

我正在开发一个 C# .NET 2.0 应用程序,其中在运行时根据环境加载两个 DLL 之一。两个 DLL 都包含相同的函数,但它们没有链接到相同的地址偏移量。我的问题是关于我的应用程序代码中的函数委托。

public class MyClass
{
    public delegate int MyFunctionDelegate(int _some, string _args);

    public MyFunctionDelegate MyFuncToCallFrmApp;

    public MyClass() : base()
    {
        this.MyFuncToCallFrmApp = new MyFunctionDelegate(this.MyFuncToCallFrmApp); // <-- Exception thrown here.
    }

    public SomeFunction()
    {
        MyFuncToCallFrmApp(int _someOther, string _argsLocal);
    }
}

当我的代码执行时,我得到一个 ArgumentException 的“委托给实例方法不能有 null 'this'”。我做错了什么?

【问题讨论】:

  • 您希望构造函数主体中的行实际实现什么?
  • @JohnB:我想知道 OP 想要完成什么。没有迹象表明他希望这条线做什么。如果他能解释这一点,我们可以试着弄清楚该怎么做。
  • @Jon:好的,我同意你的看法。例如,也许他只是难以理解代表。我也很难理解它们。

标签: c# delegates


【解决方案1】:

您需要为您的委托变量分配一个有效函数(由动态加载的 dll 中的某个类托管)。如果函数是具有同名的类的静态方法,这很简单:

public MyClass() {
    this.MyFuncToCallFrmApp = ExternalClass.Function;
}

如果函数是同名类的实例方法,只需创建一个实例并做同样的事情(还要注意,只要委托在范围内,它将防止ExternalClass实例成为垃圾-收集 - 您可能希望将实例存储为成员变量以使其更清晰):

public MyClass() {
    this.MyFuncToCallFrmApp = new ExternalClass().Function;
}

如果动态加载的类有不同的名称,您需要确定调用哪个类 - 在本例中,我使用布尔成员变量来决定是否使用默认程序集的类:

public MyClass() {
    if (this.defaultAssembly) {
        this.MyFuncToCallFrmApp = ExternalClass1.Function;
    } else {
        this.MyFuncToCallFrmApp = ExternalClass2.Function;
    }
}

【讨论】:

    【解决方案2】:

    在你的行中:

    this.MyFuncToCallFrmApp = new MyFunctionDelegate(this.MyFuncToCallFrmApp); 
    

    您在分配之前使用“this.MyFuncToCallFrmApp”,这意味着在分配期间它为空。让委托指向自己是没有意义的。这就是你想要做的吗?

    【讨论】:

      【解决方案3】:

      您正在尝试使用您的类中已经存在的委托的未初始化实例来创建委托的新实例......这没有任何意义。

      您需要使用类中的方法初始化委托,该方法具有匹配的参数列表作为委托,或者不初始化委托并允许您的类的使用者使用其代码中的匹配方法初始化委托(这是委托通常用于):

      public class MyClass
      {
          public delegate int MyFunctionDelegate(int some, string args);
          public MyFunctionDelegate MyFuncToCallFrmApp;
      
          public MyClass() : base() { }
          public SomeFunction()
          {
              if(MyFuncToCallFrmApp != null)
                  MyFuncToCallFrmApp(_someOther, _argsLocal);
          }
      }
      
      public class Consumer
      {
          MyClass instance = new MyClass();
      
          public Consumer()
          {
              instance.MyFuncToCallFrmApp = new MyFunctionDelegate(MyFunc);
          }
      
          public void MyFunc(int some, string args)
          {
              // Do Something
          }
      }
      

      【讨论】:

        【解决方案4】:

        Jim,我正在尝试自己学习 C# 中的委托。

        您的代码的一个问题是您没有将委托分配给有效的处理程序。委托的签名必须与具有相同方法签名的有效处理程序匹配。

        行内:

        this.MyFuncToCallFrmApp = new MyFunctionDelegate(this.MyFuncToCallFrmApp);
        

        this.MyFuncToCallFrmApp 是一个委托,但它需要是一个有效的方法处理程序。

        下面是你如何传入方法处理程序:

        public delegate int MyFunctionDelegate(int _some, string _args);
        
        MyFunctionDelegate MyFuncToCallFrmApp = new MyFunctionDelegate(PrintValues);
        
        // the method I'm mapping has a valid signature for the delegate I'm mapping to:
        public void PrintValues(int some, string args)
        {
          Console.WriteLine(string.Format("Some = {0} & Args = {1}", some.ToString(), args));
        }
        

        希望下面的链接和示例代码对您有所帮助:

        Delegates Tutorial

        C# 中的委托类似于 C 或 C++ 中的函数指针。使用委托允许程序员在委托对象内封装对方法的引用。然后可以将委托对象传递给可以调用引用方法的代码,而不必在编译时知道将调用哪个方法。与 C 或 C++ 中的函数指针不同,委托是面向对象的、类型安全的和安全的。 (MSDN)
        public class MyClass
        {
          // a delegate by definition is a collection of pointers to method handlers
          // I declare my delegate on this line
          // PLEASE NOTE THE SIGNATURE!
          public delegate void MyFunctionDelegate(int some, string args);
        
          public MyClass() : base()
          {
            // instantiate the delegate (AKA create the pointer)
            MyFunctionDelegate myFunctionDelegate = new MyFunctionDelegate();
        
            // map a valid method handler (WITH THE SAME SIGNATURE) to this delegate
            // I'm using "+=" operator because you can add more than one handler to a collection
            myFunctionDelegate += new MyFunctionDelegate(PrintValues);
        
            // invoke the method handler (which in this case is PrintValues() - see below)
            // NOTE THE SIGNATURE OF THIS CALL
            myFunctionDelegate(1, "Test");
          }
        
          // this is the handler method that I am going to map to the delegate
          // AGAIN, PLEASE NOTE THE SIGNATURE
          public void PrintValues(int some, string args)
          {
            Console.WriteLine(string.Format("Some = {0} & Args = {1}", some.ToString(), args));
          }
        }
        

        【讨论】:

          【解决方案5】:

          您正在尝试初始化委托以调用自身。你所做的根本没有意义。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-04-10
            • 2013-08-13
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多