Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

395
Visualizações
Create a Task (or Observable) from legacy class (start method + events)

I have a legacy class which I would like to consume in a more convenient way.

class Camera 
{
     void RequestCapture();
     public delegate void ReadResultEventHandler(ControllerProxy sender, ReadResult readResult);
     public event ReadResultEventHandler OnReadResult;
}

The class manages a camera that takes pictures. It works by:

  1. Invoking the RequestCapture method
  2. Awaiting for the OnReadResult to be raised (obviously, you need to subscribe to this event in order to get the captured data)

The operation is asynchronous. The RequestCapture is a fire-and-forget operation (fast!) operation. After some seconds, the event will raise.

I would like to consume it either like as regular Task or as an IObservable<ReadResult> but I'm quite lost, since it doesn't adapt to the Async Pattern, and I have never used a class like this.

over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

Following the example in this article my rudimentary approach (untested!!) would be:

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

Possible usage:

public async Task DoSomethingAsync()
{
    var asyncCam = new AsyncCamera(new Camera());
    var readResult = await asyncCam.CaptureAsync();
    // use readResult
}

EDIT taking Stephen's comment into account (T H A N K you!)

So, this is my naive take on unsubscribing the event handler. I didn't have the time to make any tests, so suggestions for improvement are welcome.

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

In case comments get "cleaned up": Stephen said

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

Emphasis by me.

Seems to work: https://dotnetfiddle.net/9XsaUB

over 4 years ago · Santiago Trujillo Relatório

0

You could convert the Camera.OnReadResult event to an observable sequence using the FromEvent operator:

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

Alternatively you could use the Create operator. It's more verbose, but also probably easier to comprehend.

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);
});
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda