Обратные вызовы в С#
Я хочу иметь библиотеку, которая будет иметь в ней функцию, которая принимает объект для этого параметра.
С помощью этого объекта я хочу иметь возможность вызвать указанную функцию, когда X закончен. Функция, которая будет вызываться, должна быть указана вызывающим, и X будет выполняться и контролироваться библиотекой.
Как я могу это сделать?
Для справки я использую С# и .NET 3.5
Ответы
Ответ 1
Предоставление делегата и использование анонимного делегата или выражения Lambda
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);
}
Ответ 2
Звучит как идеальный рецепт для делегатов - в частности, обратные вызовы с делегатами именно так обрабатываются в асинхронном шаблоне в .NET.
Абонент обычно передает вам какое-то состояние и делегат, и вы сохраняете их оба в любом контексте, а затем вызываете делегата, передавая ему состояние и любой результат, который у вас может быть.
Вы можете сделать состояние просто 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<...>
типы делегатов, но вы можете обнаружить, что он дает четкое объявление о себе. (Имя может уточнить, для чего вы его используете.)
Ответ 3
Объект, о котором идет речь, должен будет реализовать предоставленный вами интерфейс. Возьмите интерфейс в качестве параметра, а затем вы можете вызвать любой метод, который предоставляет интерфейс. В противном случае у вас нет способа узнать, на что способен объект. Это, или вы могли бы взять делегат в качестве параметра и вызвать его.
Ответ 4
Есть ли причина, по которой ваша библиотека не предоставляет публичное мероприятие, которое будет запущено, когда операция будет завершена? Затем вызывающий может просто зарегистрироваться для обработки события, и вам не нужно беспокоиться о передаче объектов или делегатов.
Объект, реализующий интерфейс, который вы предоставили, будет работать, но, похоже, это скорее подход Java, чем подход .NET. События кажутся мне более чистыми.
Ответ 5
Вы можете использовать System.Action, доступный в С#.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);
}
}