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

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

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

我收到的是一个错误:“modifer’static’对此项无效。”

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

这背后的原因是什么? 我使用的是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必须是一个类型,而不是一个标识符。

试试这个:

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

因此方法变量可以定义为static。 关键字staticdelegate定义没有意义,就像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()); } } 

您正在声明delegate类型。 将它声明为static没有任何意义。 但是,您可以将delegate类型的实例声明为static

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

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

一旦您将您的代表声明为:

 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 ),这可以用来代替声明自己的委托 ,这很有用:

 // you can simply use the Action delegate to declare the // method which accepts these same parameters private Action _myMoveDelegate; 

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

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

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

考虑一下:

 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运动与实际实现策略(控制台,图形,等等)分离。 之后可能需要其他策略方法,这使其成为比代表更好的选择。

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

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

 public delegate void MoveDelegate (Actor sender, MoveDirection args); public static MyClass { public static MoveDelegate MoveDelegateInstance; } 
 public static delegate void MoveDelegate (Actor sender, MoveDirection args); 

让我告诉你当你宣布代表时发生了什么

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

由于您无法通过静态类型扩展任何非静态类型。

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