为什么 .NET 委托不能声明为静态?

发布于 2024-11-26 08:43:39 字数 678 浏览 0 评论 0原文

当我尝试编译以下内容时:

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

我收到错误:“修饰符‘静态’对于此项无效。”

我在一个单例中实现这个,有一个单独的类调用委托。问题是,当我在另一个类中使用单例实例来调用委托(从标识符,而不是类型)时,无论出于何种原因,我都无法这样做,即使我将委托声明为非静态的也是如此。显然,当且仅当委托是静态的时,我才能直接通过类型引用它。

这背后的原因是什么?我正在使用 MonoDevelop 2.4.2。

更新

使用以下代码尝试其中一项建议后:

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

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

我收到一个处理错误,该错误指出 MoveMethod 必须是类型,而不是标识符。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

烟雨扶苏 2024-12-03 08:43:39

试试这个:

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

所以方法变量可以定义为静态的。关键字 static 对于 delegate 定义没有任何意义,就像 enumconst 定义一样。

如何分配静态方法字段的示例:

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

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()); 
  }
}
尛丟丟 2024-12-03 08:43:39

您正在声明一个 delegate 类型。将其声明为静态没有任何意义。不过,您可以将 delegate 类型的实例声明为 static

public delegate void BoringDelegate();


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

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 = () => { };
    }
}
热血少△年 2024-12-03 08:43:39

委托声明基本上声明了一个方法签名,其中仅包含有关其参数和返回类型的信息。由于同一个委托可以指向静态方法和实例方法,因此将方法签名本身设置为静态或实例是没有意义的。

一旦您将委托声明为:

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

这意味着该类型的任何委托都必须指向一个接受一个 Actor 参数、一个 MoveDirection 参数并返回的方法void,无论该方法是静态方法还是实例方法。您可以在命名空间范围内或在类内部声明委托(就像声明嵌套类一样)。

因此,在某处声明 MoveDelegate 后,您可以创建该类型的字段和变量:

private MoveDelegate _myMoveDelegate;

并记住该方法应该具有匹配签名:

// 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 开始)提供了一些预定义的通用委托ActionFunc< /code>) 可以使用而不是声明您自己的委托:恕

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

我直言,使用这些委托更具可读性,因为您可以通过查看委托本身立即识别参数的签名(而在您的情况下,需要查找声明)。

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

还在原地等你 2024-12-03 08:43:39

定义您的委托,在静态类中为其声明一个实例变量。

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

public static MyClass
{
     public static MoveDelegate MoveDelegateInstance;
}

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;
}
久伴你 2024-12-03 08:43:39

委托声明实际上是一种类型声明。它不能是静态的,就像不能定义静态枚举或结构一样。

但是,我宁愿使用接口而不是原始委托

考虑一下:

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

这在精神上与 策略设计模式 类似,并且允许您将 Actor 移动与实际实施策略(控制台、图形等)分离。稍后可能需要其他策略方法,这使其成为比委托更好的选择。

最后,您可以使用控制反转框架在您的 Actor 类中自动注入正确的策略实例,因此无需手动初始化。

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.

暗喜 2024-12-03 08:43:39
public static delegate void MoveDelegate (Actor sender, MoveDirection args);

让我告诉您声明委托时发生了什么。

编译器创建一个类,在本例中名为 MoveDelegate,并使用 System.MulticastDelegate 扩展它。

因为您不能通过静态类型扩展任何非静态类型。

所以这就是编译器不允许静态委托声明的原因。
但您仍然可以拥有静态委托引用。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文