从遗留 class(启动方法 + 事件)创建任务(或 Observable)
Create a Task (or Observable) from legacy class (start method + events)
我有一份遗产class,我想以更方便的方式使用它。
class Camera
{
void RequestCapture();
public delegate void ReadResultEventHandler(ControllerProxy sender, ReadResult readResult);
public event ReadResultEventHandler OnReadResult;
}
class 管理一个拍照的相机。它的工作原理是:
- 调用 RequestCapture 方法
- 等待引发 OnReadResult(显然,您需要订阅此事件才能获取捕获的数据)
操作是异步的。 RequestCapture 是一种即发即弃操作(快速!)操作。几秒钟后,事件将引发。
我想像常规 Task
或 IObservable<ReadResult>
一样使用它,但我很迷茫,因为它不适应异步模式,而且我从来没有像这样使用 class。
按照 this article 中的示例,我的基本方法(未经测试!!)将是:
class AsyncCamera
{
private readonly Camera camera;
public AsyncCamera(Camera camera)
{
this.camera = camera ?? throw new ArgumentNullException(nameof(camera));
}
public Task<ReadResult> CaptureAsync()
{
TaskCompletionSource<ReadResult> tcs = new TaskCompletionSource<ReadResult>();
camera.OnReadResult += (sender, result) => {
tcs.TrySetResult(result);
};
camera.RequestCapture();
return tcs.Task;
}
}
可能的用法:
public async Task DoSomethingAsync()
{
var asyncCam = new AsyncCamera(new Camera());
var readResult = await asyncCam.CaptureAsync();
// use readResult
}
考虑到 Stephen 的评论进行编辑(谢谢你!)
所以,这是我取消订阅事件处理程序的幼稚想法。我没有时间做任何测试,所以欢迎提出改进建议。
class AsyncCamera
{
private readonly Camera camera;
public AsyncCamera(Camera camera)
{
this.camera = camera ?? throw new ArgumentNullException(nameof(camera));
}
public Task<ReadResult> CaptureAsync()
{
ReadResultEventHandler handler = null;
TaskCompletionSource<ReadResult> tcs = new TaskCompletionSource<ReadResult>();
handler = (sender, result) => {
camera.OnReadResult -= handler;
tcs.TrySetResult(result);
};
camera.OnReadResult += handler;
camera.RequestCapture();
return tcs.Task;
}
}
以防评论被“清理”:斯蒂芬说
Unsubscription isn't handled in the MS examples, but it really should be. You'd have to declare a variable of type ReadResultDelegate (or whatever it's called), set it to null, and then set it to the lambda expression which can then unsubscribe that variable from the event. I don't have an example of this on my blog, but there's a general-purpose one here. Which, now that I look at it, does not seem to handle cancellation appropriately. – Stephen Cleary
我强调的。
您可以使用 FromEvent
运算符将 Camera.OnReadResult
事件转换为可观察序列:
var camera = new Camera();
IObservable<ReadResult> observable = Observable
.FromEvent<Camera.ReadResultEventHandler, ReadResult>(
h => (sender, readResult) => h(readResult),
h => camera.OnReadResult += h,
h => camera.OnReadResult -= h);
或者您可以使用 Create
运算符。它更冗长,但也可能更容易理解。
IObservable<ReadResult> observable = Observable.Create<ReadResult>(o =>
{
camera.OnReadResult += Camera_OnReadResult;
void Camera_OnReadResult(ControllerProxy sender, ReadResult readResult)
{
o.OnNext(readResult);
}
return Disposable.Create(() => camera.OnReadResult -= Camera_OnReadResult);
});
我有一份遗产class,我想以更方便的方式使用它。
class Camera
{
void RequestCapture();
public delegate void ReadResultEventHandler(ControllerProxy sender, ReadResult readResult);
public event ReadResultEventHandler OnReadResult;
}
class 管理一个拍照的相机。它的工作原理是:
- 调用 RequestCapture 方法
- 等待引发 OnReadResult(显然,您需要订阅此事件才能获取捕获的数据)
操作是异步的。 RequestCapture 是一种即发即弃操作(快速!)操作。几秒钟后,事件将引发。
我想像常规 Task
或 IObservable<ReadResult>
一样使用它,但我很迷茫,因为它不适应异步模式,而且我从来没有像这样使用 class。
按照 this article 中的示例,我的基本方法(未经测试!!)将是:
class AsyncCamera
{
private readonly Camera camera;
public AsyncCamera(Camera camera)
{
this.camera = camera ?? throw new ArgumentNullException(nameof(camera));
}
public Task<ReadResult> CaptureAsync()
{
TaskCompletionSource<ReadResult> tcs = new TaskCompletionSource<ReadResult>();
camera.OnReadResult += (sender, result) => {
tcs.TrySetResult(result);
};
camera.RequestCapture();
return tcs.Task;
}
}
可能的用法:
public async Task DoSomethingAsync()
{
var asyncCam = new AsyncCamera(new Camera());
var readResult = await asyncCam.CaptureAsync();
// use readResult
}
考虑到 Stephen 的评论进行编辑(谢谢你!)
所以,这是我取消订阅事件处理程序的幼稚想法。我没有时间做任何测试,所以欢迎提出改进建议。
class AsyncCamera
{
private readonly Camera camera;
public AsyncCamera(Camera camera)
{
this.camera = camera ?? throw new ArgumentNullException(nameof(camera));
}
public Task<ReadResult> CaptureAsync()
{
ReadResultEventHandler handler = null;
TaskCompletionSource<ReadResult> tcs = new TaskCompletionSource<ReadResult>();
handler = (sender, result) => {
camera.OnReadResult -= handler;
tcs.TrySetResult(result);
};
camera.OnReadResult += handler;
camera.RequestCapture();
return tcs.Task;
}
}
以防评论被“清理”:斯蒂芬说
Unsubscription isn't handled in the MS examples, but it really should be. You'd have to declare a variable of type ReadResultDelegate (or whatever it's called), set it to null, and then set it to the lambda expression which can then unsubscribe that variable from the event. I don't have an example of this on my blog, but there's a general-purpose one here. Which, now that I look at it, does not seem to handle cancellation appropriately. – Stephen Cleary
我强调的。
您可以使用 FromEvent
运算符将 Camera.OnReadResult
事件转换为可观察序列:
var camera = new Camera();
IObservable<ReadResult> observable = Observable
.FromEvent<Camera.ReadResultEventHandler, ReadResult>(
h => (sender, readResult) => h(readResult),
h => camera.OnReadResult += h,
h => camera.OnReadResult -= h);
或者您可以使用 Create
运算符。它更冗长,但也可能更容易理解。
IObservable<ReadResult> observable = Observable.Create<ReadResult>(o =>
{
camera.OnReadResult += Camera_OnReadResult;
void Camera_OnReadResult(ControllerProxy sender, ReadResult readResult)
{
o.OnNext(readResult);
}
return Disposable.Create(() => camera.OnReadResult -= Camera_OnReadResult);
});