Делегирование метода экземпляра не может иметь значение 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));
}
}