Делегирование метода экземпляра не может иметь значение null 'this'

Я разрабатываю приложение С#.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 для "Делегировать метод экземпляра не может иметь нуль 'this'". Что я делаю неправильно?

Ответ 1

Вам нужно назначить допустимую функцию (размещенную некоторым классом в динамически загруженной dll) переменной-делегату. Если функции являются статическими методами для классов с одинаковым именем, это просто:

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

Если функции являются экземплярами методов классов с одинаковым именем, просто создайте экземпляр и сделайте то же самое (также обратите внимание, что до тех пор, пока делегат находится в области видимости, это предотвратит использование экземпляра ExternalClass собрано - вы можете захотеть сохранить экземпляр как переменную-член, чтобы сделать это более понятным):

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

Если динамически загруженные классы имеют разные имена, вам нужно определить, какой из них вызывать - в этом примере я использую переменную-член типа boolean, чтобы решить, использовать ли класс сборки по умолчанию:

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

Вы пытаетесь инициализировать делегат для вызова себя. То, что вы делаете, принципиально не имеет смысла.

Ответ 5

Джим, я сам изучаю делегатов в С#.

Одна проблема с вашим кодом заключается в том, что вы не назначили делегата действительному обработчику. Подпись делегата должна соответствовать соответствующему обработчику с той же сигнатурой метода.

В строке:

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

Надеемся, что ссылка ниже и пример кода помогут вам:

Пособие для делегатов

Делегат в С# похож на указатель на функции в 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));
  }
}