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

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

5 ответов


вам нужно назначить допустимую функцию (размещенную некоторым классом в динамически загружаемой 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;
    }
}

в строку:

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

вы используете "это.MyFuncToCallFrmApp " перед его назначением, что означает, что он равен null во время назначения. Указывать делегату на самого себя не имеет смысла. Это то, что вы пытаетесь сделать?


вы пытаетесь создать новый экземпляр делегата, используя неинициализированный экземпляр делегата, который уже находится в вашем классе...в этом нет никакого смысла.

вам нужно инициализировать делегат, используя метод из вашего класса, который имеет соответствующий список аргументов в качестве делегата или не инициализирует делегат и позволяет потребителю вашего класса инициализировать делегат, используя соответствующий метод из их кода (который обычно используется делегатами 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
    }
}

Джим, я сам пытаюсь изучать делегатов на 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));
}

надеюсь, ссылка ниже и пример кода будут иметь некоторую помощь для вас:

Делегаты Учебник

делегат в 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));
  }
}

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