C#中的回调

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/667742/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 12:34:09  来源:igfitidea点击:

Callbacks in C#

c#.netcallback

提问by Malfist

I want to have a library that will have a function in it that accepts an object for it's parameter.

我想要一个库,里面有一个函数,它接受一个对象作为它的参数。

With this object I want to be able to call a specified function when X is finished. The function that will be called is to be specified by the caller, and X will be done and monitored by the library.

有了这个对象,我希望能够在 X 完成时调用指定的函数。将被调用的函数由调用者指定,X 将由库完成和监控。

How can I do this?

我怎样才能做到这一点?

For reference I'm using C# and .NET 3.5

作为参考,我正在使用 C# 和 .NET 3.5

采纳答案by bendewey

Two options for you:

两种选择:

  1. Have the function accept a delegate(Actionfor a callback that doesn't return anything, Funcfor one that does) and use an anonymous delegate or Lambda Expression when calling it.

  2. Use an interface

  1. 让函数接受一个委托Action对于不返回任何内容的回调,Func对于一个返回任何内容的回调)并在调用它时使用匿名委托或 Lambda 表达式。

  2. 使用接口

Using a delegate/lambda

使用委托/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"));
}

If your callback needs to have something passed to it, you can use a type parameter on Action:

如果你的回调需要传递一些东西,你可以在 上使用类型参数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));
}

If it needs multiple arguments, you can add more type parameters to Action. If you need a return type, as mentioned use Funcand make the return type the lasttype parameter (Func<string, int>is a function accepting a string and returning an int.)

如果它需要多个参数,你可以添加更多类型参数到Action. 如果您需要返回类型,如上所述,请使用Func并使返回类型成为最后一个类型参数(Func<string, int>是一个接受字符串并返回 int 的函数。)

More about delegates here.

更多关于这里的代表。

Using an interface

使用接口

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

回答by Ed S.

The object in question will need to implement an interface provided by you. Take the interface as a parameter, and then you can call any method that the interface exposes. Otherwise you have no way of knowing what the object is capable of. That, or you could take a delegate as a parameter and call that.

有问题的对象将需要实现您提供的接口。把接口作为参数,然后就可以调用接口暴露的任何方法。否则,您将无法知道对象的功能。那,或者您可以将委托作为参数并调用它。

回答by Jon Skeet

Sounds like a perfect recipe for delegates - in particular, callbacks with delegates are exactly how this is handled in the asynchronous pattern in .NET.

听起来像是委托的完美秘诀 - 特别是,委托回调正是在 .NET 中的异步模式中处理这种情况的方式。

The caller would usually pass you some state and a delegate, and you store both of them in whatever context you've got, then call the delegate passing it the state and whatever result you might have.

调用者通常会向您传递一些状态和一个委托,您将它们都存储在您拥有的任何上下文中,然后调用委托将状态和您可能拥有的任何结果传递给它。

You could either make the state just objector potentially use a generic delegate and take state of the appropriate type, e.g.

您可以使状态只是object或可能使用通用委托并采用适当类型的状态,例如

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

Then:

然后:

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

As you're using .NET 3.5 you might want to use the existing Func<...>and Action<...>delegate types, but you mayfind it makes it clearer to declare your own. (The name may make it clearer what you're using it for.)

当您使用 .NET 3.5 时,您可能希望使用现有 类型Func<...>Action<...>委托类型,但您可能会发现声明自己的类型更清晰。(该名称可能会更清楚地说明您使用它的目的。)

回答by Cory McCarty

Is there a reason not to have your library provide a public event to be fired when the operation is complete? Then the caller could just register to handle the event and you don't have to worry about passing around objects or delegates.

是否有理由不让您的图书馆提供在操作完成时触发的公共事件?然后调用者可以注册来处理事件,而您不必担心传递对象或委托。

The object implementing an interface you have provided would work, but it seems to be more the Java approach than the .NET approach. Events seem a bit cleaner to me.

实现您提供的接口的对象可以工作,但它似乎更像是 Java 方法而不是 .NET 方法。事件对我来说似乎更清晰一些。

回答by Vijay Bansal

You can use System.Action available in C#.NET for callback functions. Please check this sample example:

您可以将 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);
        }
    }