6

Int32と の間でデリゲート オーバーライドを定義しようとしましたIntPtr。次のオーバーロードが違法なのはなぜですか?

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

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

それはかなり奇妙に見えます。どちらも構造体ですが、異なっており、異なるインターフェースから実装されています。

考えてみると、デリゲートをオーバーロードしようとしたことはありません。それは合法ですか? もしそうなら、それはなぜですか?

更新:回答といくつかのSO投稿を確認した後、さまざまな数のパラメーターを使用してもデリゲートを宣言できないことに困惑しました。なぜこれが実行時に解決できないのか、私はまだ疑問に思っています。

4

4 に答える 4

10

考えてみると、デリゲートをオーバーロードしようとしたことはありません。それは合法ですか? もしそうなら、それはなぜですか?

いいえ、合法ではありません。現在、同じ完全修飾名を持つ2 つのを宣言しています。

型に関してオーバーロードに少し似ている唯一のことは、ジェネリック型パラメーターの数が異なる 2 つの型を宣言する場合です。たとえばAction<T>Action<T1, T2>などです。デリゲートのルールは、他のタイプのルールと同じです。

したがって、1 つのジェネリック デリゲートを宣言する (そして異なる型引数を使用する) か、2 つの異なる型名を使用する必要があります。

于 2013-06-10T16:12:31.673 に答える
5

いいえ、デリゲートをオーバーロードすることはできません。オーバーロードは、コンパイラが選択できる型情報がある場合に選択されます...しかし、デリゲートを使用すると、型情報を提供しているため、コンパイラはオーバーロードから選択する方法がありません。

同様のデリゲート型のファミリが必要な場合は、ジェネリックを使用できます。

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

EnumWindowsCallback<int>EnumWindowsCallback<IntPtr>などのさまざまなデリゲート タイプを受け入れる、オーバーロードされた p/invoke シグネチャを定義できるようになりました。

于 2013-06-10T16:12:21.573 に答える
2

すべてのデリゲート タイプは、1 つの.Invokeメソッドに限定されます。DelegateCIL を使用して、 の複数のオーバーロードから派生し、それらを含む型を定義した場合、フレームワークが正確に何をするかはわかりませんが、メソッドがInvoke1 つだけ存在するという期待は、フレームワークに十分に反映されています。Invoke

ただし、できることは、デリゲート型の代わりに使用できるインターフェイスを定義することです。たとえば、次のように定義できます。

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

その場合、実装された何かへの参照を持つコードは、InvokableAsOptionalGenericパラメーターなしで、または任意の型のパラメーターを使用して呼び出すことができます。後者の形式は、ボックス化せずに値型の引数で使用できます (一方Action<Object>、パラメータをボックス化する必要があります)。上記のスタイルの任意のインターフェースについて、インターフェースDelegate.Combineを実装する任意のオブジェクトで機能するのと同様の静的メソッドでクラスを定義できることに注意してください。コードの多くはボイラープレートになりますが、そのようなインターフェイスにはすべて独自の「結合」クラスが必要です。

于 2013-06-10T16:56:51.523 に答える
2

私はいつも「いいえ、できません」と言う人が好きではありません。;-)
したがって、私の答えは:はい、できます!

もともと、オーバーロードされた非ジェネリック メソッドをジェネリック メソッドから呼び出したいと考えていました。コンパイラはそれが好きではありませんでした。可能な解決策はSO 5666004およびSO 3905398にありますが、非常に複雑であることがわかりました。

この記事や他の投稿や記事を読んだ後、頭の片隅に漠然とした考えが浮かびました。試行錯誤と新しい機能の学習により、実用的なソリューションにたどり着きました。

他の人は正しいです。各デリゲートには個別の型があり、静的バインディングを使用するため、通常のデリゲートをオーバーロードすることはできません。ただし、抽象クラスと動的バインディング
を使用できます。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<unsigned char>^);

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<unsigned char>^ i_aucValue)
  {
    Console::WriteLine ("array<uc>");
    Thread::Sleep (2000);
  }
};

generic <class T>
ref class CData
{
public:
  CData (int i_iSize, CWorker^ i_oWorker)
  {
    m_aData = gcnew array<T>(i_iSize);
    if (T::typeid == int::typeid)
    {
      Reflection::MethodInfo^ oMethod = CWorker::typeid->GetMethod("DoWork", gcnew array<Type^>{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<Type^>{bool::typeid});
      m_delDoWork = Delegate::CreateDelegate (DelegateVB::typeid, i_oWorker, oMethod);
    }
    if (T::typeid == array<unsigned char>::typeid)
    {
      Reflection::MethodInfo^ oMethod = CWorker::typeid->GetMethod("DoWork", gcnew array<Type^>{array<unsigned char>::typeid});
      m_delDoWork = Delegate::CreateDelegate (DelegateVAUC::typeid, i_oWorker, oMethod);
    }
  }

  void DoWork (CWorker^ i_oWorker)
  {
    m_delDoWork->DynamicInvoke (gcnew array<Object^>{m_aData[0]});
    // i_oWorker->DoWork (m_aData[0]);  //--> fails with compiler error C2664: cannot convert argument...
  }

  array<T>^ m_aData;
  Delegate^ m_delDoWork;
};

int main()
{
  CWorker^ oWorker = gcnew CWorker;
  CData<bool>^ oData = gcnew CData<bool>(3, oWorker);
  oData->DoWork (oWorker);
}
于 2017-01-10T16:55:03.983 に答える