web-dev-qa-db-fra.com

Pourquoi un délégué .NET ne peut-il pas être déclaré statique?

Lorsque j'essaie de compiler les éléments suivants:

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

Je reçois, comme une erreur: "Le modificateur 'statique' n'est pas valide pour cet élément."

J'implémente ceci dans un singleton, avec une classe séparée qui appelle le délégué. Le problème est que lorsque j'utilise l'instance singleton dans l'autre classe pour appeler le délégué (à partir de l'identifiant, pas du type), je ne peux pas le faire pour une raison quelconque, même lorsque je déclare le délégué non statique. Évidemment, je ne peux y faire référence via le type directement que si et seulement si le délégué est statique.

Quel est le raisonnement derrière cela? J'utilise MonoDevelop 2.4.2.

mise à jour

Après avoir essayé l'une des suggestions avec le code suivant:

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

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

J'ai reçu une erreur de traitement, qui indique que la MoveMethod doit être un type et non un identifiant.

26
zeboidlund

Essaye ça:

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

Ainsi, la variable de méthode peut être définie comme statique. Le mot clé static n'a aucune signification pour la définition delegate, tout comme les définitions enum ou const.

Un exemple de la façon d'affecter le champ de méthode statique:

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
Chaim Zonnenberg

Vous déclarez un type delegate. Cela n'a aucun sens de le déclarer comme static. Vous pouvez cependant déclarer une instance de votre type delegate comme static.

public delegate void BoringDelegate();


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

Une déclaration de délégué déclare essentiellement une signature de méthode , qui inclut uniquement des informations sur ses paramètres et son type de retour. Et comme le même délégué peut pointer vers les méthodes statiques et d'instance, il n'est pas logique de rendre la signature de méthode elle-même statique ou d'instance.

Une fois que vous avez déclaré votre délégué comme:

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

cela signifie que tout délégué de ce type doit pointer vers une méthode qui accepte un paramètre Actor, un paramètre MoveDirection et renvoie void, que la méthode soit statique ou instance. Vous pouvez déclarer le délégué à la portée de l'espace de noms ou à l'intérieur d'une classe (tout comme vous déclareriez une classe imbriquée).

Ainsi, après avoir déclaré le MoveDelegate quelque part, vous pouvez créer des champs et des variables de ce type:

private MoveDelegate _myMoveDelegate;

et rappelez-vous que la méthode doit avoir une signature correspondante :

// 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);
}

vous pouvez ensuite affecter cette méthode à un délégué à un autre endroit:

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);
}

Il est utile de savoir que .NET (à partir de la version v3.5) fournit des délégués génériques prédéfinis (Action et Func) qui peut être utilisé au lieu de déclarer vos propres délégués :

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

L'utilisation de ces délégués est IMHO plus lisible, car vous pouvez immédiatement identifier la signature des paramètres en regardant le délégué lui-même (alors que dans votre cas, vous devez rechercher la déclaration).

5
Groo

La déclaration de délégué est en fait une déclaration de type. Il ne peut pas être statique, tout comme vous ne pouvez pas définir une énumération ou une structure statique.

Cependant, je préfère utiliser une interface au lieu d'un délégué brut .

Considère ceci:

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);
    }
}

Dans votre code d'appel:

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

Cet esprit est similaire à modèle de conception de stratégie et vous permet de découpler le mouvement Actor de la stratégie d'implémentation réelle (console, graphique, etc.). D'autres méthodes stratégiques peuvent être nécessaires plus tard, ce qui en fait un meilleur choix qu'un délégué.

Enfin, vous pouvez utiliser un Inversion of Control framework pour injecter automatiquement l'instance de stratégie correcte dans vos classes Actor donc il n'y a pas besoin d'initialisation manuelle.

2
Dan Abramov

définissez votre délégué, dans votre classe statique, déclarez-lui une variable d'instance.

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

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