2010-09-20 75 views
10

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

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“授人以实例方法不能为空‘这个’。”我究竟做错了什么?

+4

您期望构造函数体中的行能够实际实现吗? – 2010-09-20 15:18:11

+4

@JohnB:我想知道OP在试图完成什么。没有迹象表明他希望该线路做什么。如果他能解释这一点,我们可以尝试着解决该做什么。 – 2010-09-20 18:19:19

+0

@Jon:好的,我同意你的意见。例如,也许他只是无法理解代表。我也很难理解它们。 – JohnB 2010-09-20 18:35:47

回答

10

您需要指定一个有效的功能(由某些类的动态加载的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; 
    } 
} 
10

在你行:

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

您正在使用“this.MyFuncToCallFrmApp”要分配之前,这意味着它在分配的时间为null。委托自己是没有意义的。那是你正在尝试做什么?

2

您正试图初始化委托来调用它自己。你所做的从根本上说是没有道理的。

4

您试图使用已经在您的类中的委托的未初始化实例创建委托的新实例......这是没有意义的。

您需要使用您的类中具有匹配参数列表的方法作为委托来初始化委托,或者不要初始化委托并允许类的使用者使用代码中的匹配方法初始化委托(这是代表们一般都使用):

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 
    } 
} 
2

吉姆,我想学习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)); 
    } 
}