我想要一个库,其中有一个函数,它接受一个对象作为它的参数。
有了这个对象,我希望能够在 X 完成时调用指定的函数。将被调用的函数由调用者指定,X 将由库完成和监控。
我怎样才能做到这一点?
作为参考,我使用的是 C# 和 .NET 3.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"));
}
如果你的回调需要传递一些东西,你可以使用一个类型参数Action
:
public static void DoWork(Action<string> processAction)
{
// do work
if (processAction != null)
processAction("this is the string");
}
public static void Main()
{
// using anonymous delegate
DoWork(delegate(string str) { Console.WriteLine(str); });
// using Lambda
DoWork((str) => Console.WriteLine(str));
}
如果它需要多个参数,您可以将更多类型参数添加到Action
. 如果您需要返回类型,如上所述,请使用Func
并将返回类型作为最后一个类型参数(Func<string, int>
是一个接受字符串并返回 int 的函数。)
更多关于代表的信息在这里。
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);
}
听起来像是委托的完美秘诀——特别是,带有委托的回调正是 .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<...>
委托类型,但您可能会发现声明自己的类型更清晰。(这个名称可能会让您更清楚地使用它。)
有问题的对象将需要实现您提供的接口。将接口作为参数,然后就可以调用接口暴露的任何方法。否则,您将无法知道该对象的能力。那,或者您可以将委托作为参数并调用它。
是否有理由不让您的库提供在操作完成时触发的公共事件?然后调用者可以注册来处理事件,你不必担心传递对象或委托。
实现您提供的接口的对象可以工作,但它似乎更像是 Java 方法而不是 .NET 方法。事件对我来说似乎更干净一些。
您可以将 C#.NET 中可用的 System.Action 用于回调函数。请检查此示例:
//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);
}
}