C# 和事件(特别是INotifyPropertyChanged)

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

我遇到了一个非常奇怪的问题,我不能用一个小例子来重现。对不起,如果这个问题有点模糊

我有一个人的地址。两者都继承自实现INotifyPropertyChanged的BaseEntity。我希望Person类不仅在设置地址时通知PropertyChanged(“地址”),而且在地址本身更改时通知PropertyChanged(“地址”),因此我的get/set-in-Person如下所示:

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],所以事件处理程序正在被销毁(我想是在反序列化时)。