事件驱动的编程
我一直在阅读这篇MSDN文章和这个问题,试图理解.NET中的事件。 不幸的是,它没有点击我,我有很多麻烦。 我试图将这种技术整合到我的项目中,但很少成功。
基本上,我有这个班将读取数字。 每当遇到新号码时,我都希望它发起一个名为numberChanged的事件。
所以,我设置了我的事件public event EventHandler numberChanged;
。 稍后,当我遇到一个数字时,我会触发我的事件,而不是与之前的事件不同。
if(currentNumber != previousNumber){
if(numberChanged != null){
numberChanged(this, new EventArgs());
}
}
但是,我在这个事件中遇到了麻烦。 如果我做numberChanged += [something to do here]
它的错误说numberChanged是一个事件,而不是一个类型。
我的解释是否足够清晰,以提供一些建议? 非常感谢。
有很多方法来处理它,最基本的是创建一个函数:
public void MyNumberChangedHandler(object sender, EventArgs e)
{
//Your code goes here that gets called when the number changes
}
然后您通过以下方式订阅(仅限一次,通常在构造函数中):
numberChanged += MyNumberChangedHandler;
或者,您可以使用一种称为匿名(lambda)方法的方法,该方法也在您的构造函数中(通常情况下)分配:
numberChanged += (sender, e) => {
//Your code here to handle the number changed event
};
要扩大一点,使用lambda方法时必须小心,因为你可以创建内存泄漏和僵尸对象。 .NET内存垃圾收集器是一种标记扫描系统,可以在对象不再使用时删除对象。 这篇文章显示了如何去除lambda事件处理程序:如何去除lambda事件处理程序。
拥有一个活动的事件处理程序可以让对象保持活动状态, 即使它已被处置! 这是一个创建僵尸对象的例子(不在Fiddle中运行,但可以复制到自己的控制台应用程序)https://dotnetfiddle.net/EfNpZ5
打印出来:
I'm still alive I'm still alive I was disposed! Press any key to quit I'm still alive I'm still alive I'm still alive.
与C#编程世界中的其他所有事件一样,事件概念也遵循特定规则并具有自己的语法。 措辞如下:
public delegate void EventHandler(object sender, EventArgs e)
[1]。 每当你在C#中签名时,你总是知道你需要在正确的视点上写下什么或者作为参数,以便连接/调用某些对象/方法/等等。 object.event += eventHandler
(或object.event += new EventHandler(eventHandler);
) event Event SomeEvent;
)之后,剩下的就是创建一个可以绑定到该事件的方法。 这个方法必须和 EventHandler 具有相同的签名,所以它应该匹配[1]的签名,并且可以像private void numberChangedEventHandler(object sender, EventArgs eventArguments)
现在你知道你需要写在+ =的右边。
一个例子:
public class NumberSequence
{
// numbers to be compared
private readonly List<int> numbers = new List<int>();
// used to generate a random collection
private readonly Random random = new Random();
// tell me if the previous and next number are different
public event EventHandler DifferentNumbersEvent;
public NumberSequence()
{
// fill the list with random numbers
Enumerable.Range(1, 100).ToList().ForEach(number =>
{
numbers.Add(random.Next(1, 100));
});
}
public List<int> Numbers { get { return numbers; } }
public void TraverseList()
{
for (var i = 1; i < this.numbers.Count; i++)
{
if (this.numbers[i - 1] != this.numbers[i])
{
if (this.DifferentNumbersEvent != null)
{
// whoever listens - inform him
this.DifferentNumbersEvent(this, EventArgs.Empty);
}
}
}
}
}
现在在使用类之前,定义事件处理程序,它将侦听并且将在事件被触发时再次调用:
private void differentNumberEventHandler(Object sender, EventArgs eventArguments)
{
Console.WriteLine("Different numbers...");
}
用法:
var ns = new NumberSequence();
ns.DifferentNumbersEvent += differentNumberEventHandler;
ns.TraverseList();
例如:其他所有内容都只是语法糖(lambda / anonymous methods / ...)。
object.Event += (s, e) => { // code ... };
与object.Event += (Object sender, EventArgs eventArguments) => { // code ... };
相同object.Event += (Object sender, EventArgs eventArguments) => { // code ... };
。 你认出签名吗? - 它与private void differentNumberEventHandler...
。
通常我们需要通过事件传递信息,在这种情况下,我们可能希望看到这两个数字。 C#允许您使用自定义事件参数轻松完成此操作。 只需创建一个继承EventArgs
类的类并为应该传递的数据添加属性,在这种情况下为数字:
public class NumbersInfoEventArgs : EventArgs
{
public int Number1 { get; set; }
public int Number2 { get; set; }
}
然后在声明事件时指定它将传递NumbersInfoEventArgs
类型的数据(再次签名):
public event EventHandler<NumbersInfoEventArgs> DifferentNumbersEvent;
...
this.DifferentNumbersEvent(this, new NumbersInfoEventArgs
{
Number1 = this.numbers[i - 1],
Number2 = this.numbers[i]
});
最后但现在至少,事件处理程序的签名应该匹配事件的签名:
private void differentNumberEventHandler(Object sender, NumbersInfoEventArgs eventArguments)
{
Console.WriteLine("Different numbers {0} - {1}", eventArguments.Number1, eventArguments.Number2);
}
瞧,输出结果是:
Different numbers 89 - 86
Different numbers 86 - 53
Different numbers 53 - 12
Different numbers 12 - 69
您可以通过以下方式订阅活动:
using System;
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
var num = new Number();
num.numberChanged +=(s,e) =>{
Console.WriteLine("Value was changed to {0}",num.Value); // in the demo below you can find another implementation for this sample using custom events
};
num.Value=10;
num.Value=100;
}
}
public class Number{
public event EventHandler numberChanged;
private int _value=0;
public int Value
{
get{
return _value;
}
set{
if(value!=_value){
_value=value;
if(numberChanged!=null)
numberChanged(this,null);
}
}
}
}
说明:
因为EventHandler委托具有2个参数(sender,eventArgs),所以需要传递这些参数,并将它们传递为s和e
另一种方式来订阅这样的事件:
var num = new Number();
num.numberChanged += NumberChanged_Event; // below is the delegate method
public void NumberChanged_Event(object sender,EventArgs e)
{
// your code goes here
}
我更新了演示以与您自己的代理合作,传递在许多情况下可以提供帮助的旧值和新值。
这里是一个工作演示
链接地址: http://www.djcxy.com/p/51443.html下一篇: Best practices of using lambda expressions for event handlers