Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. The Lounge
  3. Why you don't create callbacks or events that don't take a state value

Why you don't create callbacks or events that don't take a state value

Scheduled Pinned Locked Moved The Lounge
linqregexfunctionalhelptutorial
12 Posts 6 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • H Offline
    H Offline
    honey the codewitch
    wrote on last edited by
    #1

    I'm wrapping a bluetooth library because i have to. So much of it is asynchronous, but it uses an event model for the asynchronicity which if you think about it makes everything more difficult. Consider the simple act of terminating a connection. It can take some time over the bluetooth protocol to do so gracefully. The library exposes a (weirdly named but okay) "OnDisconnect" event from its client object. You must hook that event to know when the disconnection is complete. (This is especially critical for methods like Connect that aren't usually fire and forget but disconnect is simpler so i'm using it here) It means you have to hook an event to find out when you can keep going, and you often have to unhook your handler from the event when you're done because next time you call disconnect or connect or whatever, you may need to do a different thing this time when it completes! Callbacks would have been easier. Worse, you can't pass any kind of state argument to Connect or Disconnect, or any other async method, which means in the real world, you pretty much have to hoist arguments and vars from your surrounding code, which means handling your events using anonymous method lambdas, which means it's very difficult to unhook your anonymous handler from the event when you're done. This kind of thing above - exposing something that should be a callback as an event, and then not allowing a state parameter is an example of how not to do it. In order to make stable code, I've been wrapping the entire library with something that uses exceptions instead of int error result values (correcting another sin) and then wrapping the event model with microsoft's awaitable TAP pattern (ie: using the familiar task framework) It's a pain in the elephant because of the mess above. This is what it looks like, even for the simplest thing. Don't do it, kids. If you're going to make code that exposes asynchronicity plan it for real world scenarios.

    public int Disconnect(int millisecondsTimeout = Timeout.Infinite)
    {
    if (_gattClient.State != wclClientState.csConnecting &&
    _gattClient.State!=wclClientState.csConnected)
    throw new InvalidOperationException("The client is not connected");
    int result = 0;
    using (var ev = new AutoResetEvent(false))
    {
    // must use a lambda for this because we need to hoist due to lack of a state value
    wclClientConnectionDisconnectEvent cde = (object sender, int reason) =>
    {
    // set the result
    result = reason;

    S Sander RosselS J M 4 Replies Last reply
    0
    • H honey the codewitch

      I'm wrapping a bluetooth library because i have to. So much of it is asynchronous, but it uses an event model for the asynchronicity which if you think about it makes everything more difficult. Consider the simple act of terminating a connection. It can take some time over the bluetooth protocol to do so gracefully. The library exposes a (weirdly named but okay) "OnDisconnect" event from its client object. You must hook that event to know when the disconnection is complete. (This is especially critical for methods like Connect that aren't usually fire and forget but disconnect is simpler so i'm using it here) It means you have to hook an event to find out when you can keep going, and you often have to unhook your handler from the event when you're done because next time you call disconnect or connect or whatever, you may need to do a different thing this time when it completes! Callbacks would have been easier. Worse, you can't pass any kind of state argument to Connect or Disconnect, or any other async method, which means in the real world, you pretty much have to hoist arguments and vars from your surrounding code, which means handling your events using anonymous method lambdas, which means it's very difficult to unhook your anonymous handler from the event when you're done. This kind of thing above - exposing something that should be a callback as an event, and then not allowing a state parameter is an example of how not to do it. In order to make stable code, I've been wrapping the entire library with something that uses exceptions instead of int error result values (correcting another sin) and then wrapping the event model with microsoft's awaitable TAP pattern (ie: using the familiar task framework) It's a pain in the elephant because of the mess above. This is what it looks like, even for the simplest thing. Don't do it, kids. If you're going to make code that exposes asynchronicity plan it for real world scenarios.

      public int Disconnect(int millisecondsTimeout = Timeout.Infinite)
      {
      if (_gattClient.State != wclClientState.csConnecting &&
      _gattClient.State!=wclClientState.csConnected)
      throw new InvalidOperationException("The client is not connected");
      int result = 0;
      using (var ev = new AutoResetEvent(false))
      {
      // must use a lambda for this because we need to hoist due to lack of a state value
      wclClientConnectionDisconnectEvent cde = (object sender, int reason) =>
      {
      // set the result
      result = reason;

      S Offline
      S Offline
      Super Lloyd
      wrote on last edited by
      #2

      It has been a long time I had to work with multiple event chains but.... Last I did, I turn them into IObservable and that help me express concisely what would have been messy otherwise... Have a look at Rx.NET and learn it a bit! :) [GitHub - dotnet/reactive: The Reactive Extensions for .NET](https://github.com/dotnet/reactive) I always despised working event and event handler and state variable, it's very spaghetti prone :(( But by turning events into Observables I can describe what I want and my conditions in very expressive and simple fashion! :)

      A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

      H 1 Reply Last reply
      0
      • S Super Lloyd

        It has been a long time I had to work with multiple event chains but.... Last I did, I turn them into IObservable and that help me express concisely what would have been messy otherwise... Have a look at Rx.NET and learn it a bit! :) [GitHub - dotnet/reactive: The Reactive Extensions for .NET](https://github.com/dotnet/reactive) I always despised working event and event handler and state variable, it's very spaghetti prone :(( But by turning events into Observables I can describe what I want and my conditions in very expressive and simple fashion! :)

        A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

        H Offline
        H Offline
        honey the codewitch
        wrote on last edited by
        #3

        I prefer, where possible to turn them into TAP patterns (async/await). That's what I'm doing with that code above. It's ugly because it hides ugly details behind a nice clean TAPpy API :)

        Real programmers use butterflies

        S 1 Reply Last reply
        0
        • H honey the codewitch

          I'm wrapping a bluetooth library because i have to. So much of it is asynchronous, but it uses an event model for the asynchronicity which if you think about it makes everything more difficult. Consider the simple act of terminating a connection. It can take some time over the bluetooth protocol to do so gracefully. The library exposes a (weirdly named but okay) "OnDisconnect" event from its client object. You must hook that event to know when the disconnection is complete. (This is especially critical for methods like Connect that aren't usually fire and forget but disconnect is simpler so i'm using it here) It means you have to hook an event to find out when you can keep going, and you often have to unhook your handler from the event when you're done because next time you call disconnect or connect or whatever, you may need to do a different thing this time when it completes! Callbacks would have been easier. Worse, you can't pass any kind of state argument to Connect or Disconnect, or any other async method, which means in the real world, you pretty much have to hoist arguments and vars from your surrounding code, which means handling your events using anonymous method lambdas, which means it's very difficult to unhook your anonymous handler from the event when you're done. This kind of thing above - exposing something that should be a callback as an event, and then not allowing a state parameter is an example of how not to do it. In order to make stable code, I've been wrapping the entire library with something that uses exceptions instead of int error result values (correcting another sin) and then wrapping the event model with microsoft's awaitable TAP pattern (ie: using the familiar task framework) It's a pain in the elephant because of the mess above. This is what it looks like, even for the simplest thing. Don't do it, kids. If you're going to make code that exposes asynchronicity plan it for real world scenarios.

          public int Disconnect(int millisecondsTimeout = Timeout.Infinite)
          {
          if (_gattClient.State != wclClientState.csConnecting &&
          _gattClient.State!=wclClientState.csConnected)
          throw new InvalidOperationException("The client is not connected");
          int result = 0;
          using (var ev = new AutoResetEvent(false))
          {
          // must use a lambda for this because we need to hoist due to lack of a state value
          wclClientConnectionDisconnectEvent cde = (object sender, int reason) =>
          {
          // set the result
          result = reason;

          Sander RosselS Offline
          Sander RosselS Offline
          Sander Rossel
          wrote on last edited by
          #4

          TL;DR, but I'm sure there's a braceless single-line if-statement in there somewhere, so prepare to be pitchforked just in case :D

          Best, Sander Azure DevOps Succinctly (free eBook) Azure Serverless Succinctly (free eBook) Migrating Apps to the Cloud with Azure arrgh.js - Bringing LINQ to JavaScript

          D 1 Reply Last reply
          0
          • Sander RosselS Sander Rossel

            TL;DR, but I'm sure there's a braceless single-line if-statement in there somewhere, so prepare to be pitchforked just in case :D

            Best, Sander Azure DevOps Succinctly (free eBook) Azure Serverless Succinctly (free eBook) Migrating Apps to the Cloud with Azure arrgh.js - Bringing LINQ to JavaScript

            D Offline
            D Offline
            Daniel Pfeffer
            wrote on last edited by
            #5

            You've got it all wrong. Mad scientists are pitchforked; witches are burnt! :D

            Freedom is the freedom to say that two plus two make four. If that is granted, all else follows. -- 6079 Smith W.

            1 Reply Last reply
            0
            • H honey the codewitch

              I prefer, where possible to turn them into TAP patterns (async/await). That's what I'm doing with that code above. It's ugly because it hides ugly details behind a nice clean TAPpy API :)

              Real programmers use butterflies

              S Offline
              S Offline
              Super Lloyd
              wrote on last edited by
              #6

              MM.,... just read a bit about... it looks like it's about turning 1 event into 1 async method... Rx.NET and Observable it's about something like LINQ to query multiple events, in any order.. not just one!

              A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

              1 Reply Last reply
              0
              • H honey the codewitch

                I'm wrapping a bluetooth library because i have to. So much of it is asynchronous, but it uses an event model for the asynchronicity which if you think about it makes everything more difficult. Consider the simple act of terminating a connection. It can take some time over the bluetooth protocol to do so gracefully. The library exposes a (weirdly named but okay) "OnDisconnect" event from its client object. You must hook that event to know when the disconnection is complete. (This is especially critical for methods like Connect that aren't usually fire and forget but disconnect is simpler so i'm using it here) It means you have to hook an event to find out when you can keep going, and you often have to unhook your handler from the event when you're done because next time you call disconnect or connect or whatever, you may need to do a different thing this time when it completes! Callbacks would have been easier. Worse, you can't pass any kind of state argument to Connect or Disconnect, or any other async method, which means in the real world, you pretty much have to hoist arguments and vars from your surrounding code, which means handling your events using anonymous method lambdas, which means it's very difficult to unhook your anonymous handler from the event when you're done. This kind of thing above - exposing something that should be a callback as an event, and then not allowing a state parameter is an example of how not to do it. In order to make stable code, I've been wrapping the entire library with something that uses exceptions instead of int error result values (correcting another sin) and then wrapping the event model with microsoft's awaitable TAP pattern (ie: using the familiar task framework) It's a pain in the elephant because of the mess above. This is what it looks like, even for the simplest thing. Don't do it, kids. If you're going to make code that exposes asynchronicity plan it for real world scenarios.

                public int Disconnect(int millisecondsTimeout = Timeout.Infinite)
                {
                if (_gattClient.State != wclClientState.csConnecting &&
                _gattClient.State!=wclClientState.csConnected)
                throw new InvalidOperationException("The client is not connected");
                int result = 0;
                using (var ev = new AutoResetEvent(false))
                {
                // must use a lambda for this because we need to hoist due to lack of a state value
                wclClientConnectionDisconnectEvent cde = (object sender, int reason) =>
                {
                // set the result
                result = reason;

                J Offline
                J Offline
                Jorgen Andersson
                wrote on last edited by
                #7

                Next post:

                honey the codewitch wrote:

                I'm wrapping creating a bluetooth library because i have to.

                Sorry, but I had to. :laugh:

                Wrong is evil and must be defeated. - Jeff Ello

                H 1 Reply Last reply
                0
                • J Jorgen Andersson

                  Next post:

                  honey the codewitch wrote:

                  I'm wrapping creating a bluetooth library because i have to.

                  Sorry, but I had to. :laugh:

                  Wrong is evil and must be defeated. - Jeff Ello

                  H Offline
                  H Offline
                  honey the codewitch
                  wrote on last edited by
                  #8

                  *cries*

                  Real programmers use butterflies

                  J 1 Reply Last reply
                  0
                  • H honey the codewitch

                    I'm wrapping a bluetooth library because i have to. So much of it is asynchronous, but it uses an event model for the asynchronicity which if you think about it makes everything more difficult. Consider the simple act of terminating a connection. It can take some time over the bluetooth protocol to do so gracefully. The library exposes a (weirdly named but okay) "OnDisconnect" event from its client object. You must hook that event to know when the disconnection is complete. (This is especially critical for methods like Connect that aren't usually fire and forget but disconnect is simpler so i'm using it here) It means you have to hook an event to find out when you can keep going, and you often have to unhook your handler from the event when you're done because next time you call disconnect or connect or whatever, you may need to do a different thing this time when it completes! Callbacks would have been easier. Worse, you can't pass any kind of state argument to Connect or Disconnect, or any other async method, which means in the real world, you pretty much have to hoist arguments and vars from your surrounding code, which means handling your events using anonymous method lambdas, which means it's very difficult to unhook your anonymous handler from the event when you're done. This kind of thing above - exposing something that should be a callback as an event, and then not allowing a state parameter is an example of how not to do it. In order to make stable code, I've been wrapping the entire library with something that uses exceptions instead of int error result values (correcting another sin) and then wrapping the event model with microsoft's awaitable TAP pattern (ie: using the familiar task framework) It's a pain in the elephant because of the mess above. This is what it looks like, even for the simplest thing. Don't do it, kids. If you're going to make code that exposes asynchronicity plan it for real world scenarios.

                    public int Disconnect(int millisecondsTimeout = Timeout.Infinite)
                    {
                    if (_gattClient.State != wclClientState.csConnecting &&
                    _gattClient.State!=wclClientState.csConnected)
                    throw new InvalidOperationException("The client is not connected");
                    int result = 0;
                    using (var ev = new AutoResetEvent(false))
                    {
                    // must use a lambda for this because we need to hoist due to lack of a state value
                    wclClientConnectionDisconnectEvent cde = (object sender, int reason) =>
                    {
                    // set the result
                    result = reason;

                    M Offline
                    M Offline
                    MarkTJohnson
                    wrote on last edited by
                    #9

                    If "The disconnect operation timed out", does that mean you are still connected?

                    I’ve given up trying to be calm. However, I am open to feeling slightly less agitated.

                    H 1 Reply Last reply
                    0
                    • M MarkTJohnson

                      If "The disconnect operation timed out", does that mean you are still connected?

                      I’ve given up trying to be calm. However, I am open to feeling slightly less agitated.

                      H Offline
                      H Offline
                      honey the codewitch
                      wrote on last edited by
                      #10

                      I wish. More likely it means your connection is in an unknown state waiting for an APC message to be dispatched that got lost somewhere.

                      Real programmers use butterflies

                      1 Reply Last reply
                      0
                      • H honey the codewitch

                        *cries*

                        Real programmers use butterflies

                        J Offline
                        J Offline
                        Jorgen Andersson
                        wrote on last edited by
                        #11

                        I expected a witty answer, now I feel bad.

                        Wrong is evil and must be defeated. - Jeff Ello

                        H 1 Reply Last reply
                        0
                        • J Jorgen Andersson

                          I expected a witty answer, now I feel bad.

                          Wrong is evil and must be defeated. - Jeff Ello

                          H Offline
                          H Offline
                          honey the codewitch
                          wrote on last edited by
                          #12

                          I'm over it. I just decided to continue writing the wrapper around this mess. :)

                          Real programmers use butterflies

                          1 Reply Last reply
                          0
                          Reply
                          • Reply as topic
                          Log in to reply
                          • Oldest to Newest
                          • Newest to Oldest
                          • Most Votes


                          • Login

                          • Don't have an account? Register

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • World
                          • Users
                          • Groups