Обратные вызовы в C#

Я хочу иметь библиотеку, в которой будет функция, которая принимает объект для его параметра.

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

Как я могу это сделать?

для справки я использую C# и .NET 3.5

5 ответов


предоставьте делегат и используйте анонимный делегат или лямбда-выражение

public static void DoWork(Action processAction)
{
  // do work
  if (processAction != null)
    processAction();
}

public static void Main()
{
  // using anonymous delegate
  DoWork(delegate() { Console.WriteLine("Completed"); });

  // using Lambda
  DoWork(() => Console.WriteLine("Completed"));
}

или использовать интерфейс

public interface IObjectWithX
{
  void X();
}

public class MyObjectWithX : IObjectWithX
{
  public void X()
  {
    // do something
  }
}

public class ActionClass
{
  public static void DoWork(IObjectWithX handlerObject)
  {
    // do work
    handlerObject.X();
  }
}

public static void Main()
{
  var obj = new MyObjectWithX()
  ActionClass.DoWork(obj);
}

звучит как идеальный рецепт для делегатов - в частности, обратные вызовы с делегатами-это именно то, как это обрабатывается в асинхронном шаблоне.Сеть.

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

вы могли бы либо сделать государство просто object или потенциально использовать универсальный делегат и принять состояние соответствующего типа, например,

public delegate void Callback<T>(T state, OperationResult result)

затем:

public void DoSomeOperation(int otherParameterForWhateverReason,
                            Callback<T> callback, T state)

поскольку вы используете .NET 3.5, вы можете использовать существующий Func<...> и Action<...> делегировать типы, но вы мая найти это делает его более четким, чтобы объявить свой собственный. (Название может прояснить, для чего вы его используете.)


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


есть ли причина, по которой ваша библиотека не предоставляет публичное событие для запуска после завершения операции? Затем вызывающий абонент может просто зарегистрироваться для обработки события, и вам не нужно беспокоиться о передаче объектов или делегатов.

объект, реализующий интерфейс, который вы предоставили, будет работать, но, похоже, это больше подход Java, чем подход .NET. События кажутся мне чище.


вы можете использовать системы.Действия, доступные в C#.NET для функций обратного вызова. Пожалуйста, проверьте этот пример:

    //Say you are calling some FUNC1 that has the tight while loop and you need to 
    //get updates on what percentage the updates have been done.
    private void ExecuteUpdates()
    {
        Func1(Info => { lblUpdInfo.Text = Info; });
    }

    //Now Func1 would keep calling back the Action specified in the argument
    //This System.Action can be returned for any type by passing the Type as the template.
    //This example is returning string.
    private void Func1(System.Action<string> UpdateInfo)
    {
        int nCount = 0;
        while (nCount < 100)
        {
            nCount++;
            if (UpdateInfo != null) UpdateInfo("Counter: " + nCount.ToString());
            //System.Threading.Thread.Sleep(1000);
        }
    }