【问题标题】:Wrapping a callback-based class to an async one将基于回调的类包装到异步类
【发布时间】:2017-08-11 11:22:38
【问题描述】:

我正在引用一个类,它使用回调而不是异步操作来执行各种要求很高的操作。例如:

class CallbackClass : SomeSdkCallbacks
{
    public void RequestData()
    {
        // We call this to request some data.
        // After some time, this will trigger OnDataReturned to be called
    }

    public void OnDataReturned(DataObject data)
    {
        // This will be called automatically with returned data via SomeSdkCallbacks
    }
}

此类结构有很多实例。

我想要做的是围绕这个创建一个包装类,以简化它的使用。我目前的结构是:

class MyWrapperClass
{
    CallbackClass CallbackClass;

    public MyWrapperClass()
    {
        this.CallbackClass = new CallbackClass();
    }

    public DataObject GetData()
    {
        this.CallbackClass.RequestData();

        // Somehow wait until this.CallbackClass.OnDataReturned is called?

        // Somehow get the data that would be passed in to this.CallbackClass.OnDataReturned()???
    }
}

将“回调”架构封装成单个异步方法的最佳方法是什么?

编辑:为了澄清,理想情况下,我想将其打包成一个方法,该方法可以在单个请求中返回数据。请参阅我的示例中的 MyWrapperClass.GetData() 方法了解我的理想结构。

编辑 2:我知道这种期望的架构是错误的形式。不幸的是,这是我要求的结构。

【问题讨论】:

  • On 开头的方法(如OnDataReturned)按照惯例是引发事件的方法,而不是处理事件的方法。看来你的架构有点问题。
  • public void OnDataReturned(DataObject data) 方法中也没有任何内容可以让您以任何方式拦截它。使用您显示的代码不可能完成您的要求。您需要向我们提供minimal reproducible example,以便我们获得有效的解决方案。
  • @Enigmativity 好点,但是该方法正在实现SomeSdkCallbacks 接口,我无法控制它。
  • 除非您对某事有一定的控制权,否则这是一个不可能回答的问题。请告诉我们你能控制什么,不能控制什么。请提供minimal reproducible example
  • @Enigmativity 你显然不明白我的问题。不过不用担心,Filip 理解并回答了它。

标签: c# .net asynchronous callback


【解决方案1】:

我想这就是你想要的:

        class CallbackClass<T>
        {
            private TaskCompletionSource<T> task = new TaskCompletionSource<T>();

            public void RequestData()
            {
               
            }

            public void OnDataReturned(T data)
            {
                task.SetResult(data);
            }

            public Task<T> Task { get { return task.Task; } }
        }

        class MyWrapperClass
        {
            public Task<DataObject> GetData()
            {
                var cls = new CallbackClass<DataObject>();

                cls.RequestData();

                return cls.Task;
            }
        }

请注意,必须为每个操作创建TaskCompletionSource,这样您就不会为两个不同的调用使用同一个。有了这个,您可以使用async 关键字。 This 可能会有所帮助。

【讨论】:

    【解决方案2】:

    在您的情况下,您可以在 CallBackClass 上添加一些事件。 喜欢这里:

    class CallbackClass : SomeSdkCallbacks
    {
        public event Action<object> DataReturnedEvent;
        public void RequestData()
        {
            // We call this to request some data.
            // After some time, this will trigger OnDataReturned to be called
        }
        public void OnDataReturned(DataObject data)
        {
            DataReturnedEvent?.Invoke(data);
        }
    }
    

    你可以在包装类中使用事件

    class MyWrapperClass
    {
        CallbackClass CallbackClass;
    
        public MyWrapperClass()
        {
            this.CallbackClass = new CallbackClass();
            CallbackClass.DataReturnedEvent =+ ProcessData;
        }
        private void ProcessData(object Data)
        {
            //some data processing
        }
        public DataObject GetData()
        {
            this.CallbackClass.RequestData()               
        }
    }
    

    【讨论】:

    • 谢谢。这样做的问题是,如果您调用MyWrapperClass.GetData(),数据实际上并没有从该调用返回。你能想出一种方法让GetData() 自己请求并返回数据吗?还是说这是不好的做法?
    • 这是实现目标的最简单方法。等一下,您从 GetData() 方法获取数据没有意义。您不知道它何时发生并且等待冻结当前线程。更好的方法是,如果您的系统在调用 GetData() 之后可以工作,并且稍后系统将对有关传递数据的事件做出反应。另一种方法是使用 asybc/await 模式,但它更困难,因为您必须根据 EAP 模式(msdn.microsoft.com/en-en/library/ms228969(v=vs.110).aspx)制作类型
    • 另外一个关于EAP的链接docs.microsoft.com/en-us/dotnet/standard/…
    猜你喜欢
    • 1970-01-01
    • 2023-03-11
    • 2021-06-26
    • 2017-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-22
    • 2014-02-19
    相关资源
    最近更新 更多