80

次のようにC#でクラスを定義することは可能ですか?

class GenericCollection<T> : SomeBaseCollection<T> where T : Delegate

私は一生、.NET 3.5 で昨夜これを達成することはできませんでした。使ってみた

delegate, Delegate, Action<T> and Func<T, T>

これはある意味許されるべきだと思います。独自の EventQueue を実装しようとしています。

私はこれをやっただけです[原始的な近似はあなたに気をつけてください]。

internal delegate void DWork();

class EventQueue {
    private Queue<DWork> eventq;
}

しかし、その後、異なるタイプの関数に対して同じ定義を再利用することができなくなります。

考え?

4

8 に答える 8

66

いくつかのクラスは一般的な制約として利用できません - Enum は別のものです。

デリゲートの場合、取得できる最も近いのは ": class" で、おそらくリフレクションを使用して (たとえば、静的コンストラクターで) Tデリゲートであることを確認します。

static GenericCollection()
{
    if (!typeof(T).IsSubclassOf(typeof(Delegate)))
    {
        throw new InvalidOperationException(typeof(T).Name + " is not a delegate type");
    }
}
于 2008-10-10T15:44:28.827 に答える
13

編集:いくつかの提案された回避策は、これらの記事で提案されています。

http://jacobcarpenters.blogspot.com/2006/06/c-30-and-delegate-conversion.html

http://jacobcarpenters.blogspot.com/2006_11_01_archive.html


C# 2.0 仕様から読み取ることができます (20.7、制約):

クラス型の制約は、次の規則を満たす必要があります。

  • 型はクラス型でなければなりません。
  • 型を封印してはなりません。
  • 型は、System.Array、System.Delegate、System.Enum、または System.ValueType のいずれかであってはなりません
  • 型はオブジェクトであってはなりません。すべての型はオブジェクトから派生するため、そのような制約が許可されていても効果はありません。
  • 特定の型パラメーターの最大 1 つの制約をクラス型にすることができます。

そして、確かにVS2008はエラーを吐き出します:

error CS0702: Constraint cannot be special class 'System.Delegate'

この問題に関する情報と調査については、こちらをお読みください

于 2008-10-10T15:52:24.210 に答える
3

Delegateはすでにチェーンをサポートしています。これはあなたのニーズを満たしていませんか?

public class EventQueueTests
{
    public void Test1()
    {
        Action myAction = () => Console.WriteLine("foo");
        myAction += () => Console.WriteLine("bar");

        myAction();
        //foo
        //bar
    }

    public void Test2()
    {
        Action<int> myAction = x => Console.WriteLine("foo {0}", x);
        myAction += x => Console.WriteLine("bar {0}", x);
        myAction(3);
        //foo 3
        //bar 3
    }

    public void Test3()
    {
        Func<int, int> myFunc = x => { Console.WriteLine("foo {0}", x); return x + 2; };
        myFunc += x => { Console.WriteLine("bar {0}", x); return x + 1; };
        int y = myFunc(3);
        Console.WriteLine(y);

        //foo 3
        //bar 3
        //4
    }

    public void Test4()
    {
        Func<int, int> myFunc = x => { Console.WriteLine("foo {0}", x); return x + 2; };
        Func<int, int> myNextFunc = x => { x = myFunc(x);  Console.WriteLine("bar {0}", x); return x + 1; };
        int y = myNextFunc(3);
        Console.WriteLine(y);

        //foo 3
        //bar 5
        //6
    }

}
于 2008-10-10T18:20:27.827 に答える
3

内部的に対処する必要がある状況に遭遇しましたDelegateが、一般的な制約が必要でした。具体的には、リフレクションを使用してイベント ハンドラーを追加したかったのですが、デリゲートにはジェネリック引数を使用したかったのです。Handler「Handler」は型変数であり、コンパイラは にキャストしないため、以下のコードは機能しませんDelegate

public void AddHandler<Handler>(Control c, string eventName, Handler d) {
  c.GetType().GetEvent(eventName).AddEventHandler(c, (Delegate) d);
}

ただし、変換を行う関数を渡すことができます。引数をconvert取り、次を返します:HandlerDelegate

public void AddHandler<Handler>(Control c, string eventName, 
                  Func<Delegate, Handler> convert, Handler d) {
      c.GetType().GetEvent(eventName).AddEventHandler(c, convert(d));
}

これでコンパイラは満足です。メソッドの呼び出しは簡単です。たとえばKeyPress、Windows フォーム コントロールのイベントにアタッチします。

AddHandler<KeyEventHandler>(someControl, 
           "KeyPress", 
           (h) => (KeyEventHandler) h,
           SomeControl_KeyPress);

SomeControl_KeyPressイベントターゲットはどこですか。重要なのはコンバーターのラムダです。これは機能しませんが、有効なデリゲートを指定したことをコンパイラーに納得させます。

(Begin 280Z28) @Justin: なぜこれを使わないのですか?

public void AddHandler<Handler>(Control c, string eventName, Handler d) { 
  c.GetType().GetEvent(eventName).AddEventHandler(c, d as Delegate); 
} 

(エンド280Z28)

于 2010-01-18T18:30:38.463 に答える
1

MSDNによると

コンパイラ エラー CS0702

制約を特別なクラス '識別子' にすることはできません。次の型は制約として使用できません:

  • System.Object
  • System.Array
  • System.Delegate
  • System.Enum
  • System.ValueType。
于 2015-04-30T08:21:17.573 に答える