我正在阅读Essential C#3.0书籍,我想知道这是否是检查代表为空的好方法?:
class Thermostat
{
public delegate void TemperatureChangeHandler ( float newTemperature );
public TemperatureChangeHandler OnTemperatureChange { get; set; }
float currentTemperature;
public float CurrentTemperature
{
get { return this.currentTemperature; }
set
{
if ( currentTemperature != value )
{
currentTemperature = value;
TemperatureChangeHandler handler = OnTemperatureChange;
if ( handler != null )
{
handler ( value );
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果类型是不可变的,解决方案是否会更改?我认为可能具有不变性,你不会遇到这个线程问题.
我最近一直在使用C#工作,我注意到在我公司的代码中引发事件的大多数代码都是这样完成的:
EventHandler handler = Initialized;
if (handler != null)
{
handler(this, new EventArgs());
}
Run Code Online (Sandbox Code Playgroud)
我真的不明白为什么相反,你不能这样做:
if (Initialized != null)
{
Initialized(this, new EventArgs());
}
Run Code Online (Sandbox Code Playgroud)
编辑:
有些值得深思,我试着对此做一些测试:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Test t = new Test(true);
while(true)
{
t.Ev += new EventHandler(t_Ev);
t.Ev -= new EventHandler(t_Ev);
}
}
static void t_Ev(object sender, EventArgs e)
{
}
}
public class Test
{
private readonly bool …Run Code Online (Sandbox Code Playgroud) 这个问题是对C#事件和线程安全问题的跟进(我不是那个问题的作者)和Eric Lippert Events and Races的相关博客文章.关于SO还有其他类似的问题,但他们都没有真正考虑过这个案例,普遍的共识是只要你取消订阅就是安全的,但我不相信这一直是真的.
根据SO问题和博客中的讨论,应该使用的模式类似于:
var ev = NotifyPropertyChanged;
if (ev != null)
ev(this, new PropertyChangedEventArgs("Foo"));
Run Code Online (Sandbox Code Playgroud)
但是如果出现以下情况怎么办:
1)我订阅了一个监听器:
mytype.NotifyPropertyChanged += Handler; // Handler is instance method in SomeObject class
Run Code Online (Sandbox Code Playgroud)
2)I(或运行时,由于作用域)在几乎同时发生属性通知的同时处理SomeObject,它包含监听器并取消订阅监听器.
3)虽然由于非常短的时间段可能发生这种情况,但理论上可能因为ev保留了不再存在的旧订户,它将在不再存在的对象中调用函数.
根据Eric Lippert的说法," 即使在事件被取消订阅之后,事件处理程序也必须是强大的." 但是如果处理程序被取消订阅并处理掉,它就不能再处理这个电话了.处理这种情况的正确方法是什么?
在try-catch中包装(1)中的代码?应该抓住什么例外?我认为ObjectDisposedException似乎很可能,但不是唯一可能发生的事件.
在C#中,你做这样的事情:
if (Changed != null)
Changed(this, EventArgs.Empty);
Run Code Online (Sandbox Code Playgroud)
但是你在VB.NET中做了什么?
有RaiseEvent,但是
RaiseEvent Changed(Me, EventArgs.Empty)
Run Code Online (Sandbox Code Playgroud)
实际上检查某事已订阅该事件?
这个Extension方法线程安全吗?
public static class Extensions
{
public static void Raise<T>(this EventHandler<T> handler,
object sender, T args) where T : EventArgs
{
if (handler != null) handler(sender, args);
}
}
Run Code Online (Sandbox Code Playgroud)
或者我需要将其改为此吗?
public static class Extensions
{
public static void Raise<T>(this EventHandler<T> handler,
object sender, T args) where T : EventArgs
{
var h = handler;
if (h!= null) h(sender, args);
}
}
Run Code Online (Sandbox Code Playgroud) 这段代码为名为的事件添加了新的EventHandler寄存器NewMail(eventargs类被命名NewMailEventArgs.
// A PUBLIC add_xxx method (xxx is the event name)
// Allows methods to register interest in the event.
public void add_NewMail(EventHandler<NewMailEventArgs> value) {
// The loop and the call to CompareExchange is all just a fancy way
// of adding a delegate to the event in a thread-safe way.
EventHandler<NewMailEventArgs> prevHandler;
EventHandler<NewMailEventArgs> newMail = this.NewMail;
do {
prevHandler = newMail;
EventHandler<NewMailEventArgs> newHandler = (EventHandler<NewMailEventArgs>)Delegate.Combine(prevHandler, value);
newMail = Interlocked.CompareExchange<EventHandler<NewMailEventArgs>>(ref this.NewMail, newHandler, prevHandler);
}
while(newMail != …Run Code Online (Sandbox Code Playgroud) 当INotifyPropertyChanged以最基本的形式实现接口时,大多数人似乎都像这样实现它::
public virtual void OnPropertyChanged(string propertyName)
{
var propertyChanged = PropertyChanged;
if (propertyChanged != null)
{
propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:为什么要额外分配var propertyChanged = PropertyChanged;?这只是一个偏好的问题,还是有充分的理由呢?当然以下是有效的吗?
public virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Run Code Online (Sandbox Code Playgroud) 基本上这已经在我的脑海里了一段时间......我想读你的意见
我从Jon Skeet那里读到了一本伟大的书:C#in Depth,Second Edition,并建议在声明自定义事件时使用类似的东西:
public event Action<string> MyEvent = delegate { };
Run Code Online (Sandbox Code Playgroud)
此声明将在触发事件之前将我们从nullity check语句中释放出来,因此不是这样:
if (this.MyEvent != null)
{
this.MyEvent("OMG osh");
}
Run Code Online (Sandbox Code Playgroud)
我们可以简单地致电:
this.MyEvent("OMG osh");
Run Code Online (Sandbox Code Playgroud)
我们的代码只会起作用.
当您声明这样的事件时,将使用空委托初始化事件,因此我们不需要检查null.
这是声明事件的另一种方式,它们是等价的
private Action<string> myDelegate;
public event Action<string> MyEvent
{
add
{
this.myDelegate += value;
}
remove
{
this.myDelegate -= value;
}
}
Run Code Online (Sandbox Code Playgroud)
欲了解更多信息:http://csharpindepth.com/Articles/Chapter2/Events.aspx
我刚刚与一些研究员进行了讨论,在工作中我们正在讨论这个主题,他们争辩说有时候我们需要立即清除事件的所有订阅,我们可以简单地为后面的委托指定null如果我们想继续使用相同的模式,我们将不得不用空委托重新初始化事件.他们还询问在多线程场景中会发生什么,这是我提出这个问题的主要原因
题
我想知道在声明此模式后的事件与检查null时是否存在一些隐藏的含义(可能在使用多线程时)
如果我使用这个模式,我实际上删除了几个if条件,这导致删除跳转语句.这在整体性能方面不会更好吗?
干杯
我正在详细阅读iNotifyPropertyChanged.
有人可以澄清为什么我们需要检查
PropertyChanged !=null?
为什么一个事件是空的?或者换句话说,为什么甚至检查它是否为空?NotifyPropertyChanged调用的唯一时间是何时PropertyChanged被引发(因此它不能为null),不是它.谁/什么可以使它为空?
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this,new PropertyChangedEventArgs(info));
}
}
Run Code Online (Sandbox Code Playgroud)
谢谢.
我注意到很多代码使用以下代码片段来调用事件处理程序.
Public event EventHandler Handler;
Protected void OnEvent(){
var handler = this.Handler;
If(null!=handler){
handler(this, new EventArgs());
}
}
Run Code Online (Sandbox Code Playgroud)
为什么Handler在调用之前将其分配给局部变量而不是Handler直接调用事件.那些之间有什么区别吗?