简体   繁体   中英

How to stop base static events/actions firing in other derived classes

I am working on an LOB application in C# using a WinForms tabbed MDI interface. I have various forms with DataGridViews to allow the user to select an object they are interested in, which they can then view/edit in a new form.

Each of my main business objects inherit from Entity, which is defined as below:

public abstract class Entity
{
    public static event Action Saved;

    internal virtual void OnSaved()
    {
        if (Saved != null)
        {
            Saved();
        }
    }
}

I then have the objects that populate the grid (these are actually auto-generated classes from Linq-to-SQL, although I can replicate the problem with normal classes):

class Class1 : Entity
{
    //Stuff
}


class Class2 : Entity
{
    //Stuff
}

I want to know when an object of a given class is modified, but i don't care which instance (hence the static action) so that i can refresh the grid and perform other activities.

The problem comes when the event is fired from a derived class instance - it fires for all other derived classes too. For example:

Class1.Saved += new Action(s1);
Class2.Saved += new Action(s2);

private void TestIt()
{
    Class2 o2 = new Class2();
    o2.OnSaved();  
}

This would fire s1 and s2, but I only want the specific one to be fired (ie s2). What is the best way to do this? I have quite a few classes that need this behviour and would like to avoid having to add any code to each class if possible.

Update:

Thank you for all your responses, they have been very helpful.

I have opted for a slightly different option, which I admit seems quite hacky, but works well for my purposes. This involves passing the type with the action and letting a handler filter and call relevant operations.

Entity Class:

public abstract class Entity
{
    public static event Action<Type> Saved;


    internal void OnSaved()
    {
        private Action<Type> SavedCopy = Saved;        

        if (SavedCopy != null)
            SavedCopy(this.GetType());
    }
}

Hook up handler:

 Entity.Saved += new Action<Type>(Handler);

Example Handler method (this will vary from form to form):

    void Handler(Type obj)
    {
       if (obj==typeof(Class1))
           UpdateGrid();
       else if (obj==typeof(Class2))
           UpdateBasicInfo();
       else if (obj == typeof(Class3))
           DoAnotherThing();
    }

Using generics could be a work around; each generic class gets a copy of the static fields.

public abstract class Entity<T>
{
    public static event Action Saved = delegate { };

    internal virtual void OnSaved()
    {
        Saved();
    }
}

class Class1 : Entity<Class1>
{
    //Stuff
}

class Class2 : Entity<Class2>
{
    //Stuff
}

You will need to have an event per type, because can't determine for which type the delegate is registered when the event is defined on the base type.

public abstract class Entity
{
    internal abstract void OnSaved();
}

class Class1 : Entity
{
    public static event Action Saved = () => { };

    internal override void OnSaved()
    {
        this.Saved();
    }

    //Stuff
}

class Class2 : Entity
{
    public static event Action Saved = () => { };

    internal override void OnSaved()
    {
        this.Saved();
    }

    //Stuff
}

I'm not sure doing it like this is a good idea, but you could specify the type when you subscribe and when you save the data:

public abstract class Entity
{
    private static Dictionary<Type, Action> Subscribers
         = new Dictionary<Type, Action>();

    internal virtual void OnSaved()
    {
        OnSaved(GetType());
    }

    private OnSaved(Type type)
    {
        Action subscribed;
        Subscribers.TryGetValue(type, out subscribed);
        if (subscribed != null)
            subscribed();
    }

    public Subscribe(Type type, Action action)
    {
        Action subscribed;
        Subscribers.TryGetValue(type, out subscribed);
        Subscribers[type] = subscribed + action;
    }

    public Unsubscribe(Type type, Action action)
    {
        Action subscribed;
        Subscribers.TryGetValue(type, out subscribed);
        Subscribers[type] = subscribed - action;
    }
}

Keep in mind that this code is not thread-safe, so if you want to use it from different threads at the same time, you need to add locking.

Why does it have to be static? Make it an instance event instead.

public event Action Saved;

You have to hook it up for each instance instead of just once per class (or, in your current case, once), but it will separate the events.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM