Pass enum elements as event args C#

2019-02-27 05:59发布

Is it possible to pass Enum elements as event arguments ?

Let's say I have..

public class Letters
{
    public delegate void StateChangedEventHandler(object sender, EventArgs e);
    public event StateChangedEventHandler StateChanged;

    public AbcState state = AbcState.Aaa;     
    public AbcState State
    {
        get{return this.state;}
        set
        {
            this.state = value;
            this.OnStateChanged();
        }
    }

    public enum AbcState
    {
        Aaa,
        Bbb,
        Ccc
    }

    protected virtual void OnStateChanged()
    {
        StateChanged?.Invoke(this, State);
    }

See how I am trying to pass the element of the enum as an event argument? Now, I normally would create a class and extends EventArgs, and then I would be able to pass the class itself. And I know I could do the same here, Create a different class extending EventArgs and then create the enum, field and property right in the class. And then make an instance of the latter into my class "Letters" (used in code above).

But, isnt that crazy ? There has to be a better way. Please tell me there is a simplier way.

By the way I do not know if the code above would compile I just wrote it straight in the Editor as I am not on my dev computer right now.

3条回答
何必那么认真
2楼-- · 2019-02-27 06:26

Nothing prevents you from not following event handler convention:

public enum Test { X }

public class A
{
    public event Action<Test> StuffDone;    
}

And you'll be able to do this:

A a = new A();
a.StuffDone += test =>
{
    if(test == Test.X)
    {

    }
};

It's just a convention, not a language limitation.

查看更多
We Are One
3楼-- · 2019-02-27 06:28

If you want the parameter of the event to be the enum, then sure, just specify that as the signature when declaring the event:

public class Letters
{
    public event Action<AbcState> StateChanged;

    private AbcState state = AbcState.Aaa;     
    public AbcState State
    {
        get{return this.state;}
        set
        {
            this.state = value;
            this.OnStateChanged();
        }
    }

    public enum AbcState
    {
        Aaa,
        Bbb,
        Ccc
    }

    protected virtual void OnStateChanged()
    {
        StateChanged?.Invoke(State);
    }
}
查看更多
倾城 Initia
4楼-- · 2019-02-27 06:44

No, it's not that crazy. It's not at all crazy to follow conventions, even if they seem a little clunky sometimes, because then those who maintain your code (including you, after you forget writing this stuff) will find as few surprises as possible.

You do have the option of using EventHandler<T>, however:

public event EventHandler<AbcState> StateChanged;

protected void OnStateChanged(AbcState state)
{
    StateChanged?.Invoke(this, state);
}

By the way, you don't have to declare a new redundant delegate type to declare an event. This is the same as your original declaration:

public event EventHandler StateChanged;

The nicest thing might be to write something like this:

public class ValueEventArgs<T> : EventArgs
{
    public ValueEventArgs(T value)
    {
        Value = value;
    }

    public T Value { get; protected set; }
}

And use it like so:

public event EventHandler<ValueEventArgs<AbcState>> StateChanged;

protected void OnStateChanged(AbcState state)
{
    StateChanged?.Invoke(this, new ValueEventArgs<AbcState>(state));
}

You could also write a ValueChangedEventArgs<T> with old and new value properties, etc. etc. But EventHandler<AbcState> is your quickest typesafe way to do what you want to.

Finally, you can use Action<T> as an event delegate, but that's a bad idea. People see Action<T> and they don't expect it to be an event. The only thing you're adding is confusion when somebody tries to read your code. Unless there is some specific, clear advantage to be had (and there's none here), don't write code which, at first glance, looks like something it isn't.

查看更多
登录 后发表回答