Why can a .NET delegate not be declared static?

后端 未结 6 2095
伪装坚强ぢ
伪装坚强ぢ 2020-12-08 19:42

When I try to compile the following:

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

I receive, as an error: \

相关标签:
6条回答
  • 2020-12-08 20:18
    public static delegate void MoveDelegate (Actor sender, MoveDirection args);
    

    Let me tell you what happened when you declared a delegate

    The compiler creates a class, in this case named MoveDelegate, and extends it with System.MulticastDelegate.

    Since you can not extend any non static type by static type.

    So this is the reason why the compiler does not allow static delegate declaration. But still you can have static delegate reference.

    0 讨论(0)
  • 2020-12-08 20:23

    You are declaring a delegate type. It doesn't make any sense to declare it as static. You could declare an instance of your delegate type as static, though.

    public delegate void BoringDelegate();
    
    
    internal class Bar {
        public static BoringDelegate NoOp;
        static Bar() {
            NoOp = () => { };
        }
    }
    
    0 讨论(0)
  • 2020-12-08 20:23

    A delegate declaration basically declares a method signature, which only includes information about its parameters and return type. And since the same delegate can point to both static and instance methods, it doesn't make sense to make the method signature itself static or instance.

    Once you have declared your delegate as:

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

    it means that any delegate of this type must point to a method which accepts one Actor parameter, one MoveDirection parameter, and returns void, regardless of whether the method is static or instance. You can declare the delegate at namespace scope, or inside a class (just like you would declare a nested class).

    So after declaring the MoveDelegate somewhere, you can the create fields and variables of that type:

    private MoveDelegate _myMoveDelegate;
    

    and remember that the method should have a matching signature:

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

    then you can assign this method to a delegate at some other place:

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

    It is useful to know that .NET (starting from version v3.5) provides some predefined generic delegates (Action and Func) which can be used instead of declaring your own delegates:

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

    Using those delegates is IMHO more readable, since you can immediately identify parameters' signature from looking at the delegate itself (while in your case one needs to look for the declaration).

    0 讨论(0)
  • 2020-12-08 20:33

    Delegate declaration is actually a type declaration. It cannot be static, just like you cannot define a static enum or structure.

    However, I would rather use an interface instead of raw delegate.

    Consider this:

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

    In your calling code:

    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
    

    This similar in spirit to Strategy design pattern and allows you to decouple Actor movement from the actual implementation strategy (console, graphic, whatever). Other strategy methods may later be required which makes it a better choice than a delegate.

    Finally, you can use an Inversion of Control framework to automatically inject correct strategy instance in your Actor classes so there is no need for manual initialization.

    0 讨论(0)
  • 2020-12-08 20:36

    Try this:

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

    So the method-variable can be defined static. The keyword static has no meaning for the delegate definition, just like enum or const definitions.

    An example of how to assign the static method-field:

    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()); 
      }
    }
    
    0 讨论(0)
  • 2020-12-08 20:38

    define your delegate, in your static class declare an instance variable for it.

    public delegate void MoveDelegate (Actor sender, MoveDirection args);
    
    public static MyClass
    {
         public static MoveDelegate MoveDelegateInstance;
    }
    
    0 讨论(0)
提交回复
热议问题