and events (特别是INotifyPropertyChanged):和事件

3

我遇到了一个非常奇怪的问题,我似乎无法用一个简单的例子来重现。如果这个问题有点模糊,对不起。

我有一个包含地址信息的人员类(Person),和一个继承自BaseEntity并实现了INotifyPropertyChanged接口的地址类(Address)。我希望在设置Address属性时,Person类能够触发NotifyPropertyChanged("Address")事件,并且在Address本身发生更改时也能触发该事件,因此我的Person类的get/set方法如下:

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"); };
        }
    }

    ...
}

这个方法已经运行了几个月,现在我给Person、Address和BaseEntity添加了[Serializable](并且在BaseEntity的PropertyChanged中添加了[field: NonSerialized]),但是当我更改Address时(例如somePerson.Address.Street =“something new”),该地址的PropertyChanged的调用计数为0,而以前它是1,因此Person没有得到通知,并且不会触发NotifyPropertyChanged("Address")。

如果我从Person中删除[Serializable],它可以正常工作,如果我重新添加它,则无法正常工作。实际上我还没有序列化任何东西,我只是添加了[Serializable]属性。

有什么想法吗?

4个回答

2
你的Person/Address/BaseEntity被序列化/反序列化了,然后出现了这种行为,还是仅仅添加了[Serializable]属性就导致了这种行为?
我之所以问对象是否被反序列化并且展示这种行为,是因为在我大多数实现INotifyPropertyChanged的情况下,我明确将PropertyChanged事件标记为不可序列化,并在适当时手动重新挂接事件。(序列化事件会扩展对象图并可能导致意外对象的序列化。)
如果你的对象没有序列化事件,那么在反序列化时,它们似乎没有触发任何事件。它们可能已经被触发,但是没有人再监听了。

值得注意的是,BinaryFormatter序列化字段而不是属性...因此,在反序列化时,属性设置器不会被调用,也不会重新挂接PropertyChanged事件。 - Jeff
好的,我应该澄清一下,我的评论是基于我使用BinaryFormatter的经验。 - Yoopergeek
仅仅添加 [Serializable] 特性就导致了这种行为。 - epalm
@epalm 注意,将对象添加到缓存或类似的操作可能涉及序列化。 - Marc Gravell
2
@epalm - 找出问题的简单方法是实现ISerializable接口(并添加适当的构造函数),然后在其中设置断点。这将告诉您它是否已序列化。或者甚至只需添加一个序列化回调函数。 - Marc Gravell
显示剩余5条评论

2
我猜测(在评论中的讨论略有推动)你的应用程序中某个代码正在检测 [Serializable] 并决定对对象进行序列化。例如,缓存可能是一个合适的候选者,任何“深度克隆”代码也可能如此。尝试实现 ISerializable(或仅添加序列化回调),并添加断点。如果断点触发,请加载调用堆栈窗口并向上导航到查看是什么序列化了您的对象以及原因。

我添加了一个带有断点的[OnSerialized]回调函数,这是堆栈跟踪:http://dl.dropbox.com/u/4220513/stacktrace.txt。看起来像是WCF,谁说“噢,嘿,它是可序列化的,所以我猜我现在要序列化它”,因为在BaseEntity的PropertyChanged事件上有[field: NonSerialized],所以事件处理程序被销毁了(在反序列化时,我猜)。 - epalm

1

BaseEntity中的PropertyChanged事件已经具有此属性。 - epalm

1
我进行了一个小测试,发现在是否将类设为可序列化之间没有任何区别。以下是一些可行的示例代码。
    [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]属性导致了这种行为。我没有(主动地)进行序列化。 - epalm
@epalm 我写了一个小的测试应用程序,无法重现您看到的错误。您可能希望将我所做的与您的实际代码进行比较,以查看是否有任何实质性差异。 - Darryl Braaten

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接