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

时间:2011-07-26 19:55:02

标签: c# delegates compiler-errors

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

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必须是一个类型,而不是标识符。

6 个答案:

答案 0 :(得分:32)

试试这个:

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

答案 1 :(得分:8)

您要声明delegate类型。将它声明为static没有任何意义。不过,您可以将delegate类型的实例声明为static

public delegate void BoringDelegate();


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

答案 2 :(得分:5)

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

将您的代表声明为:

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<Actor, MoveDirection> _myMoveDelegate;

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

答案 3 :(得分:2)

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

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

考虑一下:

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

这与Strategy design pattern的精神相似,允许您将Actor移动与实际实施策略(控制台,图形,等等)分离。之后可能需要其他策略方法,这使其成为比代表更好的选择。

最后,您可以使用Inversion of Control frameworkActor类中自动注入正确的策略实例,这样就不需要手动初始化了。

答案 4 :(得分:0)

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

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

public static MyClass
{
     public static MoveDelegate MoveDelegateInstance;
}

答案 5 :(得分:-1)

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

让我告诉你在宣布委托时发生的事情

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

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

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

相关问题