web-dev-qa-db-ja.com

.NETデリゲートを静的に宣言できないのはなぜですか?

以下をコンパイルしようとすると:

public static delegate void MoveDelegate (Actor sender, MoveDirection args);

「このモディファイヤ 'static'はこのアイテムでは無効です。」というエラーが表示されます。

デリゲートを呼び出す別のクラスを使用して、これをシングルトン内に実装しています。問題は、他のクラス内のシングルトンインスタンスを使用してデリゲートを(型ではなく識別子から)呼び出す場合、デリゲートを静的でないと宣言した場合でも、何らかの理由でそれを実行できないことです。明らかに、デリゲートが静的である場合のみ、型を介して直接参照することができます。

これの背後にある理由は何ですか? MonoDevelop 2.4.2を使用しています。

更新

次のコードで提案の1つを試した後:

public void Move(MoveDirection moveDir)
{
    ProcessMove(moveDir);
}

public void ProcessMove(MoveDirection moveDir)
{
    Teleporter.MoveMethod mm = new Teleporter.MoveMethod(Move); 
    moveDelegate(this, moveDir);
}

MoveMethodはタイプではなく、識別子でなければならないことを示す処理エラーを受け取りました。

26
zeboidlund

これを試して:

public delegate void MoveDelegate(object o);
public static MoveDelegate MoveMethod;

したがって、method-variableは静的に定義できます。キーワードstaticは、delegateまたはenum定義と同様に、const定義には意味がありません。

静的メソッドフィールドを割り当てる方法の例:

public class A
{
  public delegate void MoveDelegate(object o);
  public static MoveDelegate MoveMethod;
}

public class B
{
  public static void MoveIt(object o)
  {
    // Do something
  }    
}

public class C
{
  public void Assign()
  {
    A.MoveMethod = B.MoveIt;
  }

  public void DoSomething()
  {
    if (A.MoveMethod!=null)
      A.MoveMethod(new object()); 
  }
}
33

delegate型を宣言しています。 staticとして宣言しても意味がありません。ただし、delegateタイプのインスタンスをstaticとして宣言することもできます。

public delegate void BoringDelegate();


internal class Bar {
    public static BoringDelegate NoOp;
    static Bar() {
        NoOp = () => { };
    }
}
8
jason

デリゲート宣言は基本的にメソッドシグネチャを宣言します。これには、パラメーターと戻り値の型に関する情報のみが含まれます。また、同じデリゲートが静的メソッドとインスタンスメソッドの両方を指すことができるため、メソッドシグネチャ自体を静的またはインスタンスにすることは意味がありません。

デリゲートを次のように宣言したら、

public delegate void MoveDelegate (Actor sender, MoveDirection args);

これは、このタイプのデリゲートが1つのActorパラメータ、1つのMoveDirectionパラメータ、およびvoidを受け入れるメソッドを指す必要があることを意味します。メソッドが静的かインスタンスか。名前空間スコープまたはクラス内でデリゲートを宣言できます(ネストされたクラスを宣言するのと同じように)。

したがって、MoveDelegateをどこかで宣言した後、そのタイプのフィールドと変数を作成できます。

private MoveDelegate _myMoveDelegate;

また、メソッドにはmatchingシグネチャが必要です。

// parameters and return type must match!
public void Move(Actor actor, MoveDirection moveDir)
{
    ProcessMove (moveDir);
}

public static void MoveStatic(Actor actor, MoveDirection moveDir)
{
    ProcessMove (moveDir);
}

次に、このメソッドを他の場所のデリゲートに割り当てることができます。

private void SomeOtherMethod()
{
     // get a reference to the Move method
     _myMoveDelegate = Move;

     // or, alternatively the longer version:
     // _myMoveDelegate = new MoveDelegate(Move);

     // works for static methods too
     _myMoveDelegate = MoveStatic;

     // and then simply call the Move method indirectly
     _myMoveDelegate(someActor, someDirection);
}

.NET(バージョンv3.5以降)がいくつかの事前定義済みgeneric delegatesAction and Func)を提供し、使用できることを知っていると役立ちます独自のデリゲートを宣言する代わりに

// you can simply use the Action delegate to declare the
// method which accepts these same parameters
private Action<Actor, MoveDirection> _myMoveDelegate;

これらのデリゲートを使用すると、デリゲート自体を確認することでパラメーターのシグネチャを即座に識別できるため(この場合は宣言を探す必要があります)、IMHOの方が読みやすくなります。

5
Groo

デリゲート宣言は、実際には型宣言です。静的な列挙型や構造体を定義できないのと同じように、静的にすることはできません。

ただし、代わりに生のデリゲートの代わりにインターフェイスを使用します。

このことを考慮:

public interface IGameStrategy {
    void Move(Actor actor, MoveDirection direction);
}

public class ConsoleGameStrategy : IGameStrategy {
    public void Move(Actor actor, MoveDirection direction)
    {
        // basic console implementation
        Console.WriteLine("{0} moved {1}", actor.Name, direction);
    }
}

public class Actor {
    private IGameStrategy strategy; // hold a reference to strategy

    public string Name { get; set; }    

    public Actor(IGameStrategy strategy)
    {
        this.strategy = strategy;
    }

    public void RunForrestRun()
    {
        // whenever I want to move this actor, I may call strategy.Move() method

        for (int i = 0; i < 10; i++)
            strategy.Move(this, MoveDirection.Forward);
    }
}

あなたの呼び出しコードで:

var strategy = new ConsoleGameStrategy();

// when creating Actors, specify the strategy you want to use
var actor = new Actor(strategy) { Name = "Forrest Gump" };
actor.RunForrestRun(); // will write to console

これは精神的に Strategy design pattern に似ており、Actorの動きを実際の実装戦略(コンソール、グラフィックなど)から切り離すことができます。後で他の戦略メソッドが必要になる可能性があり、デリゲートよりも優れた選択肢になります。

最後に、 Inversion of Control framework を使用して、正しい戦略インスタンスをActorクラスに自動的に挿入できるため、手動で初期化する必要はありません。

2
Dan Abramov

デリゲートを定義し、静的クラスでインスタンス変数を宣言します。

public delegate void MoveDelegate (Actor sender, MoveDirection args);

public static MyClass
{
     public static MoveDelegate MoveDelegateInstance;
}
0
Darryl Braaten