Delegate to an instance method cannot have null &#

2019-02-21 13:23发布

问题:

I am developing a C# .NET 2.0 application wherein at run-time one of two DLLs are loaded depending on the environment. Both DLLs contain the same functions, but they are not linked to the same address-offset. My question is regarding the function delegates in my application code.

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);
    }
}

When my code executes I get an ArgumentException of "Delegate to an instance method cannot have null 'this'." What am I doing wrong?

回答1:

You need to assign a valid function (hosted by some class in the dynamically loaded dll) to your delegate variable. If the functions are static methods on classes with the same name, this is straightforward:

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

If the functions are instance methods of classes with the same name, just create an instance and do the same thing (also note that as long as the delegate is in scope, it will prevent the ExternalClass instance from being garbage-collected - you may want to store the instance as a member variable to make that clearer):

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

If the dynamically-loaded classes have different names, you'll need to determine which one to call - in this example, I'm using a boolean member variable to decide whether or not to use a default assembly's class:

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


回答2:

In your line:

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

You are using "this.MyFuncToCallFrmApp" before you are assigning it, which means it is null during the time of assignment. Making a delegate point to itself makes no sense. Is that what you are trying to do?



回答3:

You're trying to create a new instance of a delegate using the uninitialized instance of the delegate that is already in your class...which makes no sense.

You need to initialize the delegate using a method from your class that has a matching arguments list as your delegate or don't initialize the delegate and allow the consumer of your class to initialize the delegate using a matching method from their code (which is what delegates are normally used for):

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, I'm trying to learn delegates in C# myself.

One problem with your code is that you have not assigned the delegate to a valid handler. The signature of the delegate has to be matched to a valid handler with the same method signature.

In the line:

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

this.MyFuncToCallFrmApp is a delegate, but it needs to be a valid method handler instead.

Here is how you pass in a method handler:

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));
}

Hopefully the link below and sample code will be of some help to you:

Delegates Tutorial

A delegate in C# is similar to a function pointer in C or C++. Using a delegate allows the programmer to encapsulate a reference to a method inside a delegate object. The delegate object can then be passed to code which can call the referenced method, without having to know at compile time which method will be invoked. Unlike function pointers in C or C++, delegates are object-oriented, type-safe, and secure. (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:

You're trying to initialize the delegate to call itself. What you're doing fundamentally doesn't make sense.



标签: c# delegates