0

I'm programming an event system, where every listener listens to one, multiple or all channels (GameEventChannel enum) and and event can be raised only for one, multiple or all channels (GameEventChannels). What i have right now is.

[System.Flags]
public enum GameEventChannel {
    One = 1,
    Two = 2,
    Three = 4,
    Four = 8,
    Five = 16,
    Six = 32,
    Seven = 64,
    Eight = 128,
    Nine = 256,
    Ten = 512
}

The event gets invoked by another class, which calls Invoke(GameEventChannel channel) on it. Inside the Invoke function, i iterate over all listening listeners for this event, and want to determine which listeners it should invoke

public void Invoke(GameEventChannel channels)
    {
        Debug.Log("Invoke with channales: " + channels.ToString());
        for (var i = 0; i < _Listeners.Count; i++)
        {
            var listener = _Listeners[i];
            if (listener != null && IsListeningToChannel())
            {
                _Listeners[i]?.OnEventInvoked();
            }
        }
    }

I need to code out the function IsListeningToChannel() which needs to decide if the listeners is listening on this GameEventChannel the event wants to invoke.

e.g.

Event.Invoke(GameEventChannel.One | GameEventChannel.Two | GameEventChannel.Three)

Listener1 is listening to "GameEventChannel.Two | GameEventChannel.Eight"

How can i check if Listener1 should be invoked, because he listens on GameEventChannel.Two which Event wants to call.

All Code

  public enum GameEventChannel {
        One = 1,
        Two = 2,
        Three = 4,
        Four = 8,
        Five = 16,
        Six = 32,
        Seven = 64,
        Eight = 128,
        Nine = 256,
        Ten = 512
    }    

    public void Invoke(GameEventChannel channels)
    {

        for (var i = 0; i < _Listeners.Count; i++)
        {
            var listener = _Listeners[i];
            if (listener != null && IsListeningToChannel())
            {
                _Listeners[i]?.OnEventInvoked();
            }
        }
    }

     public bool IsListeningToChannel(GameEventChannel listenerChannel, GameEventChannel eventChannels)
    {
        return AnyOfListenerChanelFlagInsideEventChannelFlags;
    }

Edit 1: Changed every occurance of the enum to the right name Edit 2: Added complete code for enum (includes attribute now)

  • Your enumeration is in violation of numerous design guidelines which are designed to help you use this pattern correctly. For example, you should use the `[Flags]` attribute on such an enumeration. You should also provide a `None = 0` member. – Eric Lippert Aug 15 '19 at 20:23
  • [`Enum.HasFlag(Enum)`](https://learn.microsoft.com/en-us/dotnet/api/system.enum.hasflag?view=netframework-4.8) should be of help here. – Good Night Nerd Pride Aug 15 '19 at 20:27
  • 1
    @GoodNightNerdPride: Unfortunately not quite; `HasFlag` means "does the given value have *all* of the given flags?" but it sounds like Black Phoenix wants the semantics "does the given value have *any* of the given flags?" – Eric Lippert Aug 15 '19 at 20:30
  • It is rather confusing that you seem to go back and forth between the enum being named `Channel` and `GameEventChannel`. What's going on here? – Eric Lippert Aug 15 '19 at 20:32
  • Thanks for your answers. I take following the guidelines into consideration. Enum.HasFlag(..) only checks for given value to match all flags, like @EricLippert answered. – BlackPhoenix134 Aug 15 '19 at 21:59

1 Answers1

4

Though Steve's answer -- now mysteriously deleted -- is correct, it could be improved.

First, build your enumeration correctly. Flag enums should be marked as such and should have a None value. You might also consider using binary literals to make it more clear.

[Flags] public enum Channel 
{
  None = 0b0000_0000_0000,
  One  = 0b0000_0000_0001,
  Two  = 0b0000_0000_0010,
  ...

My recommendation is that you implement an extension method that computes what you want, and is named appropriately. For example, if what you want is "has any of the given channels":

static class Extensions 
{
  public static bool HasAnyChannel(
      this Channel x,
      Channel y) =>
    x & y != Channel.None;
}

And now you can use the expression

listenerChannels.HasAnyChannel(eventChannels)

which is easy to read and understand.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 1
    Enum has [Flag] Attribute, just forgot to copy it into my post Thanks for pointing that out. Thanks for you solution – BlackPhoenix134 Aug 15 '19 at 22:02
  • `x & y != GameEventChannel.None;` Gives: "Cannot apply operator '&' of operands of type 'GameEventChannel' and 'bool'" Fix: `(x & y) != GameEventChannel.None;` – BlackPhoenix134 Aug 16 '19 at 12:46