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. General Programming
  3. C#
  4. Why am I not allowed to do this with events

Why am I not allowed to do this with events

Scheduled Pinned Locked Moved C#
questioncsharpdatabasewpfagentic-ai
3 Posts 2 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.
  • K Offline
    K Offline
    Keith Barrow
    wrote on last edited by
    #1

    This is a genuine "why" question (as in the technical reason why the language prohibits what I want to do) rather than a "how do I get round the limitation?"* I'm writing a WPF app and implementing a base class for a Command. The base implementation contains common logic to a set of subclasses which must have the Database connection in a non-busy state before they can execute. If the busy state changes, calling CanExecuteChanged?.Invoke(this, e); is naturally fine in this base. The problem is I have secondary conditions in the subclasses which also prevent execution - on those conditiond changing I'd want to call CanExecuteChanged?.Invoke(this, e); from the subclass - this isn't allowed and I can't work out the reasoning. My current working theory is the even is like syntactic sugar over a delegates (or something) and the part to raise the event is private (which would prevent raising outside the base class) the whereas the subscription side is public (so you can subscribe from an unrelated type).That doesn't explain why the "raise" part isn't protected, or somehow optionally private/protected. There is a gap in my knowledge somewhere. * I have a couple of solutions for this: like exposing the delegate with a backing field and calling that, or the one I'll probably adopt which is to expose a protected event to raise the event seems more explicit.

    KeithBarrow.net[^] - It might not be very good, but at least it is free!

    Richard DeemingR 1 Reply Last reply
    0
    • K Keith Barrow

      This is a genuine "why" question (as in the technical reason why the language prohibits what I want to do) rather than a "how do I get round the limitation?"* I'm writing a WPF app and implementing a base class for a Command. The base implementation contains common logic to a set of subclasses which must have the Database connection in a non-busy state before they can execute. If the busy state changes, calling CanExecuteChanged?.Invoke(this, e); is naturally fine in this base. The problem is I have secondary conditions in the subclasses which also prevent execution - on those conditiond changing I'd want to call CanExecuteChanged?.Invoke(this, e); from the subclass - this isn't allowed and I can't work out the reasoning. My current working theory is the even is like syntactic sugar over a delegates (or something) and the part to raise the event is private (which would prevent raising outside the base class) the whereas the subscription side is public (so you can subscribe from an unrelated type).That doesn't explain why the "raise" part isn't protected, or somehow optionally private/protected. There is a gap in my knowledge somewhere. * I have a couple of solutions for this: like exposing the delegate with a backing field and calling that, or the one I'll probably adopt which is to expose a protected event to raise the event seems more explicit.

      KeithBarrow.net[^] - It might not be very good, but at least it is free!

      Richard DeemingR Offline
      Richard DeemingR Offline
      Richard Deeming
      wrote on last edited by
      #2

      The technical reason is fairly simple. When you declare an event:

      public class Foo
      {
      public event EventHandler Test;
      }

      the compiler actually generates two members:

      public class Foo
      {
      [CompilerGenerated]
      [DebuggerBrowsable(DebuggerBrowsableState.Never)]
      private EventHandler Test;

      public event EventHandler Test
      {
          \[CompilerGenerated\]
          add
          {
              EventHandler eventHandler = this.Test;
              EventHandler eventHandler2;
              do
              {
                  eventHandler2 = eventHandler;
                  EventHandler value2 = (EventHandler)Delegate.Combine(eventHandler2, value);
                  eventHandler = Interlocked.CompareExchange(ref this.Test, value2, eventHandler2);
              }
              while ((object)eventHandler != eventHandler2);
          }
          \[CompilerGenerated\]
          remove
          {
              EventHandler eventHandler = this.Test;
              EventHandler eventHandler2;
              do
              {
                  eventHandler2 = eventHandler;
                  EventHandler value2 = (EventHandler)Delegate.Remove(eventHandler2, value);
                  eventHandler = Interlocked.CompareExchange(ref this.Test, value2, eventHandler2);
              }
              while ((object)eventHandler != eventHandler2);
          }
      }
      

      }

      Inside the same type, you will either reference the private field (for assignment, Invoke, etc.) or the event (for adding and removing handlers). The compiler will decide which. Outside of the class, you only have access to the event. All you can do is add or remove a handler. I believe this is to prevent other classes from raising events without the cooperation of the base class, or swapping out the entire list of handlers. But obviously you'd need to ask the original language designers to know their reasoning. Of course, the simple workaround is to provide a protected method in the base class which raises the event on demand.

      protected void OnTest(EventArgs e)
      {
      Test?.Invoke(this, e);
      }


      "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

      "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

      K 1 Reply Last reply
      0
      • Richard DeemingR Richard Deeming

        The technical reason is fairly simple. When you declare an event:

        public class Foo
        {
        public event EventHandler Test;
        }

        the compiler actually generates two members:

        public class Foo
        {
        [CompilerGenerated]
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        private EventHandler Test;

        public event EventHandler Test
        {
            \[CompilerGenerated\]
            add
            {
                EventHandler eventHandler = this.Test;
                EventHandler eventHandler2;
                do
                {
                    eventHandler2 = eventHandler;
                    EventHandler value2 = (EventHandler)Delegate.Combine(eventHandler2, value);
                    eventHandler = Interlocked.CompareExchange(ref this.Test, value2, eventHandler2);
                }
                while ((object)eventHandler != eventHandler2);
            }
            \[CompilerGenerated\]
            remove
            {
                EventHandler eventHandler = this.Test;
                EventHandler eventHandler2;
                do
                {
                    eventHandler2 = eventHandler;
                    EventHandler value2 = (EventHandler)Delegate.Remove(eventHandler2, value);
                    eventHandler = Interlocked.CompareExchange(ref this.Test, value2, eventHandler2);
                }
                while ((object)eventHandler != eventHandler2);
            }
        }
        

        }

        Inside the same type, you will either reference the private field (for assignment, Invoke, etc.) or the event (for adding and removing handlers). The compiler will decide which. Outside of the class, you only have access to the event. All you can do is add or remove a handler. I believe this is to prevent other classes from raising events without the cooperation of the base class, or swapping out the entire list of handlers. But obviously you'd need to ask the original language designers to know their reasoning. Of course, the simple workaround is to provide a protected method in the base class which raises the event on demand.

        protected void OnTest(EventArgs e)
        {
        Test?.Invoke(this, e);
        }


        "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

        K Offline
        K Offline
        Keith Barrow
        wrote on last edited by
        #3

        Oh wow thanks, that's exactly what I was hoping for. It's also along the the "syntactic sugar" line of thinking. I've been off C# as my main work for 4/5years now so I'm getting to grips with it all again. I won't utter the name of the language I have been principally using, but it rhymes with Lavascript :~

        KeithBarrow.net[^] - It might not be very good, but at least it is free!

        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