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.
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());
}
}
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 = () => { };
}
}
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).
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.
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;
}