Подтвердить что ты не робот

Почему .NET делегат не может быть объявлен статическим?

Когда я пытаюсь скомпилировать следующее:

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 должен быть типом, а не идентификатором.

4b9b3361

Ответ 1

Попробуйте следующее:

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

Ответ 2

Вы объявляете тип delegate. Не имеет смысла объявлять его как static. Вы могли бы объявить экземпляр вашего типа delegate как static, однако.

public delegate void BoringDelegate();


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

Ответ 3

Объявление делегата в основном объявляет подпись метода, которая включает только информацию о ее параметрах и возвращаемом типе. И поскольку тот же делегат может указывать как на статические, так и на экземплярные методы, не имеет смысла заставить старую или экземпляр самой сигнатуры метода.

Как только вы объявили своего делегата как:

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) предоставляет некоторые предопределенные общие делегаты (Action и Func), которые можно использовать вместо объявления ваши собственные делегаты:

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

Использование этих делегатов является IMHO более читабельным, так как вы можете сразу определить подпись параметров из просмотра самого делегата (в то время как в вашем случае нужно искать объявление).

Ответ 4

Объявление делегата - это объявление типа. Он не может быть статическим, так же, как вы не можете определить статическое перечисление или структуру.

Однако я предпочитаю использовать интерфейс вместо необработанного делегата.

Рассмотрим это:

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, поэтому нет необходимости в ручной инициализации.

Ответ 5

определите своего делегата, в вашем статическом классе объявите для него переменную экземпляра.

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

public static MyClass
{
     public static MoveDelegate MoveDelegateInstance;
}

Ответ 6

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

Позвольте мне рассказать вам, что произошло, когда вы объявили делегата

Компилятор создает класс в этом случае с именем MoveDelegate и расширяет его с помощью System.MulticastDelegate.

Так как вы не можете расширять какой-либо нестатический тип статическим типом.

Так вот почему компилятор не разрешает статическое объявление делегата. Но все же у вас может быть статическая ссылка делегата.