将事件指定给事件以供以后使用

时间:2011-08-05 10:27:44

标签: c# events design-patterns

这很难说,所以我将主要依赖代码。

顺便说一句,如果你能更好地解答问题不要犹豫,给你的2c!

class CustomEventArgs : EventArgs
{
    public delegate void CustomEventHandler( Object sender, CustomEventArgs args );

    public int data;

    public CustomEventArgs (int _data)
    {
        data = _data;
    }
}

这是我们将在此示例中使用的事件。

class EventGenerator
{
    public event CustomEventArgs.CustomEventHandler WeOccasion;

    public EventGenerator ()
    {
        Task.Factory.StartNew( () =>
            {
                var index = 1;

                // just loop and generate events every now and then
                while (true)
                {   
                    Thread.Sleep( 1000 );
                    WeOccasion( this, new CustomEventArgs (++index));
                }
            });
    }
}

这个类只是循环触发CustomEventHandler事件。

class EventActivity
{
    // EventActivity has an event of the same type as EventGenerator's 
    public event CustomEventArgs.CustomEventHandler WeOccasion;

    // this is the part I cant seem to get right
    public event CustomEventArgs.CustomEventHandler Source ( get; set; }

    public bool Active {
        set
        {
            if (value)
            {
                Source += DoWork;
            }
            else
            {
                Source -= DoWork;
            }
        }
    }

    private void DoWork( Object sender, CustomEventArgs frame);
}

这是我真正需要帮助的地方。我想要一个指向另一个类CustomEventHandler中的事件的指针,稍后我可以在激活活动时为其分配事件处理程序。

以下是包含在类中的用法示例;

class EventAssigner
{
    EventGenerator Generator;
    EventActivity DoSomeThing1;
    EventActivity DoSomeThing2;

    public EventAssigner ()
    {
        // init
        Generator = new EventGenerator();
        DoSomeThing1 = new EventActivity();
        DoSomeThing2 = new EventActivity();

        // assign sources
        DoSomeThing1.Source = Generator.WeOccasion;
        DoSomeThing2.Source = DoSomeThing1.WeOccasion;

        // activate the first activity
        DoSomeThing1.Active = true;
    }

    public void Activate2()
    {
        // activate the second activity
        DoSomeThing2.Active = true;
    }

    public void Deactivate2()
    {
        // deactivate the second activity
        DoSomeThing2.Active = false;
    }
}

很明显这段代码不起作用,我想这就是我所要求的。你能让这种设计模式起作用吗?

2 个答案:

答案 0 :(得分:2)

您要求做的事情对于.NET事件来说是不可能的,并且可能并不像您想象的那样令人满意。一些背景应该有助于解释原因:

属性具有get和set操作的基本模式。通过访问属性(对于get)和对属性的赋值(对于集合)来调用它们:

var x = instance.Prop1; // access
instance.Prop1 = x; // assignment

当您从课堂外访问某个活动时(例如instance.Event),您将获得" public" face,与属性一样,有两个操作:添加处理程序和删除处理程序。这些是使用+=-=运算符调用的。

instance.Event += this.Handler; // add
instance.Event -= this.Handler; // remove

重要的是要注意它没有"得到"操作 - 无法获得对课外活动的引用;你只能修改注册的处理程序。

当您从班级中访问某个活动时,您将获得" private" face,它本质上是注册事件处理程序的委托(函数指针)的特殊集合。当您调用委托时,您实际上要求框架迭代已注册的事件处理程序并调用它们。

if(this.Event != null)
{
    this.Event.Invoke(e, args); // raise event
}

公共面孔和私人面孔的分离使您可以拥有一个简单的event关键字,它可以为您提供一个神奇的事件。它也阻止你传递对事件的引用。

要将事件传递给注册方法,您必须传递事件所附加的对象。如果你有多个类实现相同的事件并且你想以相同的方式注册它们,你应该让它们实现一个事件的接口(是的,事件可以在接口上)并编写你的方法接受接口为一个论点。

答案 1 :(得分:1)

如果我读错了你想要的话

DoSomeThing1.Source = Generator.WeOccasion;

将指针保存到WeOccasion事件,以便稍后可以向其添加DoWork调用,对吧?

我不认为使用“普通”代码是可能的,因为事件不是值,而是属性。请考虑以下类似代码:

myProp = aPerson.Name; // attempt to save the name property for later
myProp = "Fred"; // intent is to set aPerson.Name = "Fred"

如果你希望这个工作,我建议使用反射来查找事件,并使用EventInfo.AddEventHandler方法添加它(http://msdn.microsoft.com/en-us/library/system.reflection .eventinfo.addeventhandler.aspx)