C# 和事件(特别是INotifyPropertyChanged)
我遇到了一个非常奇怪的问题,我不能用一个小例子来重现。对不起,如果这个问题有点模糊 我有一个人的地址。两者都继承自实现INotifyPropertyChanged的BaseEntity。我希望Person类不仅在设置地址时通知PropertyChanged(“地址”),而且在地址本身更改时通知PropertyChanged(“地址”),因此我的get/set-in-Person如下所示:C# 和事件(特别是INotifyPropertyChanged),c#,events,inotifypropertychanged,serializable,C#,Events,Inotifypropertychanged,Serializable,我遇到了一个非常奇怪的问题,我不能用一个小例子来重现。对不起,如果这个问题有点模糊 我有一个人的地址。两者都继承自实现INotifyPropertyChanged的BaseEntity。我希望Person类不仅在设置地址时通知PropertyChanged(“地址”),而且在地址本身更改时通知PropertyChanged(“地址”),因此我的get/set-in-Person如下所示: class Person : BaseEntity { private Address addres
class Person : BaseEntity
{
private Address address;
public Address Address
{
get { return address; }
set
{
address = value;
NotifyPropertyChanged("Address");
// propagate changes in Address to changes in Person
address.PropertyChanged += (s, e) => { NotifyPropertyChanged("Address"); };
}
}
...
}
这几个月来一直运作良好
我已经将[Serializable]添加到Person、Address和BaseEntity中(并将[field:NonSerialized]添加到BaseEntity的PropertyChanged中),现在当我更改地址(somePerson.Address.Street=“Someone new”)时,地址的PropertyChanged调用计数为0,以前为1,所以Person不会收到通知,而且它本身不触发NotifyPropertyChanged(“地址”)
同样,如果我从Person中删除[Serializable],它会工作,如果我重新添加它,它就不会工作。我实际上还没有序列化任何东西,我只是添加了[Serializable]属性
有什么想法吗?是您的Person/Address/BaseEntity被序列化/反序列化,然后表现出这种行为,还是仅仅是[Serializable]属性的附加部分导致了这种行为 我询问对象是否正在被反序列化,然后表现出这样的行为,因为在我的大部分INotifyPropertyChanged实现中,我明确地将PropertyChanged事件标记为非序列化,然后在反序列化时手动重新钩住事件。(序列化事件会扩展对象图,并可能导致意外对象的序列化。) 如果您的对象没有序列化事件,那么在反序列化时,它们似乎没有触发是有意义的。他们可能被抚养长大了,但没有人再听了。看看是否添加:
[field:NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
这就是诀窍
最初来自:我做了一个小测试,让类序列化和不序列化没有区别。下面是一些工作示例代码
[Serializable]
public class BaseEntity : INotifyPropertyChanged
{
[NonSerialized]
private PropertyChangedEventHandler _propertyChanged;
public event PropertyChangedEventHandler PropertyChanged
{
add { _propertyChanged += value; }
remove { _propertyChanged -= value; }
}
protected void NotifyPropertyChanged(string propertyName)
{
_propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
[Serializable]
public class Person : BaseEntity
{
private Address _address;
public Address Address
{
get { return _address; }
set
{
_address = value;
NotifyPropertyChanged("Address");
Address.PropertyChanged += (s, e) =>
{
Console.WriteLine("Address Property Changed {0}", e.PropertyName);
NotifyPropertyChanged("Address");
};
}
}
}
[Serializable]
public class Address : BaseEntity
{
private string _city;
public string City
{
get { return _city; }
set
{
_city = value;
NotifyPropertyChanged("City");
}
}
}
static void Main(string[] args)
{
var person = new Person();
person.PropertyChanged += (s, e) => Console.WriteLine("Property Changed {0}", e.PropertyName);
person.Address = new Address();
person.Address.City = "TestCity";
}
程序输出为
属性更改地址
地址财产变更城市
属性更改地址我的猜测(从评论中的讨论中有点刺激)是应用程序中的某些代码正在检测[Serializable]
并决定序列化对象。例如,缓存可能是一个候选对象,就像任何“深度克隆”代码一样
尝试实现ISerializable(或只添加序列化回调),并添加断点。如果遇到断点,请加载调用堆栈窗口并导航回堆栈以查看序列化对象的原因。另外值得注意的是,BinaryFormatter序列化字段,而不是属性…因此,在反序列化时,不会调用属性设置器,也不会重新读取PropertyChanged事件。这一点很好,我应该澄清我的评论是根据我使用BinaryFormatter的经验得出的。只需添加导致此行为的[Serializable]属性即可。@epalm除非涉及某些序列化,否则我觉得很难相信。。。真的需要看一个可复制的例子。我的建议-复制一个损坏的版本,一次简化一个版本,直到它工作为止-嘿,presto,解决了(也就是说,你会发现关键的区别)@epalm-找到答案的简单方法-实现ISerializable(并添加适当的构造函数),并在其中设置一个断点。这会告诉你它是否被序列化了。甚至可能只是添加序列化回调。BaseEntity中的PropertyChanged事件已具有此属性。只需添加导致此行为的[Serializable]属性即可。我没有(主动)序列化任何内容。@epalm我编写了一个小测试应用程序,无法重现您看到的错误。您可能希望将我所做的与实际代码进行比较,以查看是否存在任何实质性差异。我添加了一个带有断点的[OnSerialized]回调,下面是stacktrace:。看起来可能是WCF,他说“哦,嘿,它是可序列化的,所以我想我现在就序列化它”,因为我在BaseEntity的PropertyChanged事件上有[field:NonSerialized],所以事件处理程序正在被销毁(我想是在反序列化时)。