为什么.NET委托不能声明为静态的
本文关键字:静态 声明 不能 NET 为什么 | 更新日期: 2023-09-27 18:03:42
当我尝试编译以下内容时:
public static delegate void MoveDelegate (Actor sender, MoveDirection args);
我收到一个错误:"修改程序‘static’对此项目无效。">
我在一个单例中实现了这一点,使用一个单独的类来调用委托。问题是,当我使用另一个类中的singleton实例来调用委托(来自标识符,而不是类型(时,无论出于什么原因,我都不能这样做,即使我声明委托为非静态的。显然,我只能通过类型直接引用它,当且仅当委托是静态的。
这背后的原因是什么?我使用的是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
对于delegate
的定义没有任何意义,就像enum
或const
的定义一样。
如何分配静态方法字段的示例:
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(从3.5版开始(提供了一些预定义的通用委托(Action
和Func
(非常有用,这些委托可以使用,而不是声明自己的委托:
// you can simply use the Action delegate to declare the
// method which accepts these same parameters
private Action<Actor, MoveDirection> _myMoveDelegate;
使用这些委托使IMHO更具可读性,因为您可以通过查看委托本身立即识别参数的签名(而在您的情况下,需要查找声明(。
委托声明实际上是一个类型声明。它不能是静态的,就像不能定义静态枚举或结构一样。
但是,我宁愿使用接口,而不是原始委托。
考虑一下:
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
类中自动注入正确的策略实例,这样就不需要手动初始化。
定义您的委托,在您的静态类中为其声明一个实例变量。
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
对其进行扩展。
由于您不能通过静态类型来扩展任何非静态类型。
所以这就是编译器不允许静态委托声明的原因。但是仍然可以有静态委托引用。