34

When I try to compile the following:

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

I receive, as an error: "The modifer 'static' is not valid for the this item."

I'm implementing this within a singleton, with a separate class which calls the delegate. The problem is that when I use the singleton instance within the other class to call the delegate (from the identifier, not the type), I can't do that for whatever reason, even when I declare the delegate non-static. Obviously, I can only refer to it via the type directly if and only if the delegate is static.

What is the reasoning behind this? I am using MonoDevelop 2.4.2.

update

After trying one of the suggestions with the following code:

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

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

I've received a processing error, which states that the MoveMethod must be a type, and not an identifier.

Anthony Mastrean
  • 21,850
  • 21
  • 110
  • 188
zeboidlund
  • 9,731
  • 31
  • 118
  • 180
  • I think a little code example will help you explaining the problem. I read second paragraph five times and still have no idea what and how you want to accomplish. – Dan Abramov Jul 26 '11 at 20:07
  • What is the purpose of the `mm` variable in the `ProcessMove` method? If some delegate (either static or instance) is assigned to `moveDelegate`, then calling `moveDelegate` will call the assigned delegate, as it should. – vgru Jul 26 '11 at 20:40
  • I think interfaces are better for this. Please see [my answer](http://stackoverflow.com/questions/6835766/c-delegate-cannot-be-declared-static/6835948#6835948) – Dan Abramov Jul 26 '11 at 22:14

6 Answers6

45

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()); 
  }
}
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Chaim Zonnenberg
  • 1,793
  • 13
  • 10
  • I'm not quite following. Is that supposed to be a public field, or a method? If it's a field, is it supposed to refer to an instance of a delegate? When I try to reference it within my other class, I get an error :/. – zeboidlund Jul 26 '11 at 20:12
  • I added an example. As you can see, the static method-variable works like a static field. – Chaim Zonnenberg Jul 26 '11 at 20:21
  • The statement " just like enum or const definitions" does not sound correct. const is by default static in nature so we cant have static for const type fields. Example given is good. – Dhananjay Nov 21 '13 at 14:03
  • Hi C.Zonnenberg, Is it mandatory in C# for the method `B.MoveIt` be static? And why? – Abhi Mar 01 '18 at 06:53
9

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 = () => { };
    }
}
jason
  • 236,483
  • 35
  • 423
  • 525
  • 1
    It might "make sense" and in fact be quite useful to be able to declare a `delegate` which can never represent an instance method, i.e. which would not be a managed `__thiscall`, but rather a necessarily static managed method (on a static or instance class). Such a "delegate" type would have no `Delegate.Target` property, and it's instances would have no provision for storing a `this` object... perhaps a base class for the existing `Delegate` type? The advantage would be emitting `call` instead of `callvirt` in the IL, which might also avoid stacking a null `this` value. – Glenn Slayden Apr 17 '17 at 00:36
9

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).

vgru
  • 49,838
  • 16
  • 120
  • 201
  • Your comments about the signature of a delegate are ok, but unrelated to the issue of whether the delegate *instance* represents a static vs. instance *method*. That *could* be what the OP was reaching for... at least that's how I ended up on this page. Perhaps your answer might make mention of the fact that two instances of the same delegate type can represent methods with ostensibly the same signature, but where one is static and the other instance. It's a significant difference which should be understood, despite C#'s efforts to obscure it. See my other comment for further motivations. – Glenn Slayden Apr 17 '17 at 00:53
  • I just found a discussion of the (unholy, IMHO) relationship between static vs. instance delegates at https://msdn.microsoft.com/en-us/library/z84bd3st(v=vs.110).aspx. There's a particularly good code example at the bottom. – Glenn Slayden Apr 17 '17 at 01:05
  • @Glenn: perhaps I should update the answer, but the truth is that delegates in .NET can point to both instance and static methods, and stores the information about the target internally. Actually, there are several different ways it can store this, like explained [here](http://mattwarren.org/2017/01/25/How-do-.NET-delegates-work/) under "Different types of delegates". Internal type of the delegate will determine how the parameters will be arranged on the stack by the JITter to match the actual target signature, while allowing calling code to transparently pass parameters to the delegate. – vgru Apr 17 '17 at 08:16
  • The runtime difference between instance and static methods is basically in the implicit `this` parameter, i.e. the *instance* reference for the instance method. In the simplest case (closed delegate type), delegates pointing to instance methods will have the instance in its `_target` field, while delegates pointing to static methods will have the first parameter stored there. .NET usually uses (at least it used to) *closed* instance delegates and *open* static delegates, meaning that generally, instance method calls (through a delegate) are faster because they don't need a shuffle thunk. – vgru Apr 17 '17 at 08:26
  • 1
    Yes, and my point is that all of that is way too much functional variation to lump into a single opaque vehicle. I'm only arguing for more prominently exposing distinctions that do already exist, and that you in fact corroborate (c.f. "Different types of delegates", to which my view might quip, "Where?!…"). A static vs. instance distinction for delegates, plus appropriate administrative regime, would raise awareness and help preclude painful but common coding errors, the worst being how static lambdas are silently promoted to instance when a local inadvertently falls into the closure. – Glenn Slayden Apr 17 '17 at 10:21
  • 1
    "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" To me (and hopefully others) this is gold! Thank you for this over and above a really good and clear answer – Arkaine80 Sep 03 '21 at 12:39
1

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.

Community
  • 1
  • 1
Dan Abramov
  • 264,556
  • 84
  • 409
  • 511
  • I'm trying to write a text based game engine which allows me to create objects and move them around the map, displaying their object coordinates to the console. This is to be done before any GUI, graphics, etc. is added. I'm at the point where I decided to create a teleporter class, which I made a singleton, to use to move any object around to a specific destination. For now I keep it simple: MoveDirection.Forward, or MoveDirection.Backward. If you want me to post source, let me know. – zeboidlund Jul 26 '11 at 20:19
  • @Holland: I'd rather go with interfaces (if I got your problem right). Please see my edit. – Dan Abramov Jul 26 '11 at 22:07
0
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.

Draken
  • 3,134
  • 13
  • 34
  • 54
0

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;
}
Darryl Braaten
  • 5,229
  • 4
  • 36
  • 50