Posso definire 2 delegati con lo stesso nome ma diversi parametri?

Ho provato a definire un override delegato tra Int32 e IntPtr . Perché i seguenti sovraccarichi sono illegali?

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

Sembra abbastanza strano. Sono entrambe le strutture, ma sono diverse e implementano da diverse interfacce.

Vieni a pensarci, non ho mai provato a sovraccaricare un delegato prima. È legale, e se sì, perché?

AGGIORNAMENTO: Dopo aver esaminato le risposte e altri post SO, ero sconcertato che i delegati non possano essere dichiarati anche con un numero variabile di parametri. Mi sto ancora chiedendo perché questo non può essere risolto in fase di esecuzione.

Vieni a pensarci, non ho mai provato a sovraccaricare un delegato prima. È legale, e se sì, perché?

No, non è legale. Attualmente stai dichiarando due tipi con lo stesso nome completo.

L’unica cosa che assomiglia un po ‘a un sovraccarico quando si tratta di tipi è se si dichiarano due tipi che differiscono nel numero di parametri di tipo generico. Ad esempio, Action , Action ecc. Le regole per i delegati non sono diverse dalle regole per altri tipi qui.

Pertanto, è necessario dichiarare un delegato generico (e utilizzare argomenti di tipo diverso) oppure utilizzare due nomi di tipi diversi.

No, non puoi sovraccaricare un delegato. I sovraccarichi vengono selezionati quando sono disponibili informazioni sul tipo per il compilatore per selezionarne uno … ma con un delegato, si forniscono le informazioni sul tipo e il compilatore non avrebbe modo di selezionare tra sovraccarichi.

Se si desidera una famiglia di tipi di delegati simili, è ansible utilizzare i generici.

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

Ora è ansible definire le firme p / invoke sovraccariche che accettano diversi tipi di delegati EnumWindowsCallback , EnumWindowsCallback , ecc.

Tutti i tipi di delegati sono limitati a un singolo metodo .Invoke . Non sono sicuro di cosa farebbe esattamente il Framework se si usasse CIL per definire un tipo derivato da Delegate e includesse più overload di Invoke , ma l’aspettativa che solo un metodo Invoke esista è ben supportato nel Framework.

Ciò che si può essere in grado di fare, tuttavia, è definire un’interfaccia che si può usare al posto del tipo delegato. Ad esempio, si potrebbe definire qualcosa come:

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

nel qual caso il codice che aveva un riferimento a qualcosa che implementava InvokableAsOptionalGeneric poteva chiamarlo senza parametri, o con un parametro di qualsiasi tipo; la seconda forma potrebbe essere utilizzata con argomenti di tipo value senza box (mentre Action dovrebbe inserire il parametro). Si noti che per qualsiasi interfaccia dello stile di cui sopra, si potrebbe definire una class con un metodo statico simile a Delegate.Combine che funzionerebbe con qualsiasi object che implementa l’interfaccia; ogni interfaccia di questo tipo avrebbe bisogno della propria class “combinatoria”, anche se gran parte del codice sarebbe di tipo standard.

Non mi piace quella gente che dice sempre “no, non puoi” . 😉
Quindi la mia risposta è: sì, puoi!

Inizialmente volevo chiamare un metodo non generico sovraccarico da un metodo generico. Al compilatore non piaceva. Le possibili soluzioni sono in SO 5666004 e SO 3905398 , ma le ho trovate abbastanza complicate.

Dopo aver letto questo e altri post e articoli, ho avuto qualche idea confusa nella parte posteriore della mia mente. Prova ed errore, e learing nuove funzioni mi ha portato a una soluzione di lavoro.

Gli altri hanno ragione, non è ansible sovraccaricare i delegati normali, poiché ogni delegato ha il suo tipo individuale e utilizza il binding statico.
Ma puoi usare la class Delegate astratta e l’associazione dynamic.

Ecco la soluzione pronta per la compilazione e l’esecuzione (scritta in 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); }