简体   繁体   English

如何停止其他派生类中的基本静态事件/动作触发

[英]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. 我正在使用WinForms选项卡式MDI界面在C#中处理LOB应用程序。 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. 我有各种带有DataGridViews的表单,以允许用户选择他们感兴趣的对象,然后他们可以以新表单查看/编辑。

Each of my main business objects inherit from Entity, which is defined as below: 我的每个主要业务对象都继承自Entity,其定义如下:

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): 然后,我有了填充网格的对象(这些实际上是从Linq-to-SQL自动生成的类,尽管我可以用普通的类来复制问题):

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). 这将触发s1和s2,但我只希望触发特定的一个(即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. 我选择了一个稍有不同的选项,我承认这似乎很hacky,但对于我的目的来说效果很好。 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. 您必须为每个实例连接它,而不是每个类一次(或者在当前情况下为一次),但是它将分隔事件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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