我可以定义具有相同名称但不同参数的2个代理吗?

我试图在Int32IntPtr之间定义一个委托覆盖。 为什么以下超载非法?

 public delegate int EnumWindowsCallback (System.IntPtr hWnd, int lParam); public delegate int EnumWindowsCallback (System.IntPtr hWnd, System.IntPtr lParam); 

这看起来很奇怪。 它们都是结构但是不同并且从不同的接口实现。

想想看,我从来没有尝试过代理过代表。 它甚至是合法的,如果是的话,为什么?

更新:在完成答案和更多SOpost之后,我感到困惑的是,即使使用不同数量的参数也无法声明代表。 我仍然想知道为什么在运行时无法解决这个问题。

想想看,我从来没有尝试过代理过代表。 它甚至是合法的,如果是的话,为什么?

不,这不合法。 您目前正在声明具有相同完全限定名称的两种类型

在类型方面,唯一看起来有点像重载的是,如果声明两种类型,它们的generics类型参数的数量不同。 例如, ActionAction等。委托的规则与此处其他类型的规则没有什么不同。

因此,您需要声明一个通用委托(并使用不同的类型参数),或使用两个不同的类型名称。

不,你不能重载委托。 当有类型信息可供编译器选择时,选择重载…但是使用委托, 您提供类型信息 ,编译器无法从重载中进行选择。

如果您想要一个类似的委托类型系列,您可以使用generics。

 public delegate int EnumWindowsCallback(System.IntPtr hWnd, LParamType lParam); 

现在您可以定义重载的p / invoke签名,它们接受不同的委托类型EnumWindowsCallbackEnumWindowsCallback等。

所有委托类型都限制为单个.Invoke方法。 我不确定如果使用CIL来定义从Delegate派生的类型并包含Invoke多个重载,那么Framework究竟会做什么,但是只有一个Invoke方法存在的期望很好地支持到Framework中。

然而,人们可以做的是定义一个可以用来代替委托类型的接口。 例如,可以定义如下内容:

 interface IInvokableAsOptionalGeneric { void Invoke(); void Invoke(T param); } 

在这种情况下,具有对实现InvokableAsOptionalGeneric的引用的代码可以在没有参数的情况下调用它,或者使用任何类型的参数调用它; 后一种forms可以与值类型参数一起使用而不需要装箱(而Action必须将参数装箱)。 请注意,对于上述样式的任何接口,可以使用类似于Delegate.Combine的静态方法定义一个类,该方法可以与实现该接口的任何对象一起使用; 每个这样的接口都需要自己的“组合”类,尽管大部分代码都是样板文件。

我不喜欢那些总是说“不,你不能”的人 。 😉
因此我的答案是: 是的,你可以!

最初我想从generics方法调用重载的非generics方法。 编译器不喜欢这样。 可能的解决方案在SO 5666004和SO 3905398中 ,但我发现它们非常复杂。

在阅读了这篇以及其他post和文章之后,我脑海里浮现出一些模糊的想法。 试验和错误,以及学习新function让我找到了一个有效的解决方案。

其他的是正确的,你不能重载正常的委托,因为每个委托都有它的个人类型并使用静态绑定。
但是您可以使用抽象的Delegate类和动态绑定。

这是准备编译并运行的解决方案(用C ++ / CLI编写):

 using namespace System; using namespace System::Collections::Generic; using namespace System::Threading; delegate void DelegateVI (int); delegate void DelegateVB (bool); delegate void DelegateVAUC (array^); ref class CWorker { public: void DoWork (int i_iValue) { Console::WriteLine ("int"); Thread::Sleep (500); } void DoWork (bool i_bValue) { Console::WriteLine ("bool"); Thread::Sleep (1000); } void DoWork (array^ i_aucValue) { Console::WriteLine ("array"); Thread::Sleep (2000); } }; generic  ref class CData { public: CData (int i_iSize, CWorker^ i_oWorker) { m_aData = gcnew array(i_iSize); if (T::typeid == int::typeid) { Reflection::MethodInfo^ oMethod = CWorker::typeid->GetMethod("DoWork", gcnew array{int::typeid}); m_delDoWork = Delegate::CreateDelegate (DelegateVI::typeid, i_oWorker, oMethod); } else if (T::typeid == bool::typeid) { Reflection::MethodInfo^ oMethod = CWorker::typeid->GetMethod("DoWork", gcnew array{bool::typeid}); m_delDoWork = Delegate::CreateDelegate (DelegateVB::typeid, i_oWorker, oMethod); } if (T::typeid == array::typeid) { Reflection::MethodInfo^ oMethod = CWorker::typeid->GetMethod("DoWork", gcnew array{array::typeid}); m_delDoWork = Delegate::CreateDelegate (DelegateVAUC::typeid, i_oWorker, oMethod); } } void DoWork (CWorker^ i_oWorker) { m_delDoWork->DynamicInvoke (gcnew array{m_aData[0]}); // i_oWorker->DoWork (m_aData[0]); //--> fails with compiler error C2664: cannot convert argument... } array^ m_aData; Delegate^ m_delDoWork; }; int main() { CWorker^ oWorker = gcnew CWorker; CData^ oData = gcnew CData(3, oWorker); oData->DoWork (oWorker); }