一般来说,在处理实现了 INotifyPropertyChanged 的对象时,我应该依赖哪些线程安全保证?
当一个对象实现INotifyPropertyChanged接口时,它的成员PropertyChanged是一个用于拦截属性改变动作的事件处理程序,应该在我们的代码中实现,然后我们还需要创建方法/函数来处理这个事件,从而确保多个线程在对该对象进行操作时不会发生冲突。例如:
public class Test1 : INotifyPropertyChanged
{
private string _test;
public string test
{
get { return _test; }
set
{
if (value != _test)
{
_test = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName]string propertyName = "")
{
if (this.PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
现在的问题是PropertyChanged事件如何保证它的安全,如果你使用ILSpy查看INotifyPropertyChanged Interface的源代码,你会发现在它里面,它只是实现了一个委托PropertyChanged,并且委托是这样的:
using System;
using System.Security.Permissions;
namespace System.ComponentModel
{
/// <summary>Represents the method that will handle the <see cref="E:System.ComponentModel.INotifyPropertyChanged.PropertyChanged" /> event raised when a property is changed on a component.</summary>
/// <param name="sender">The source of the event. </param>
/// <param name="e">A <see cref="T:System.ComponentModel.PropertyChangedEventArgs" /> that contains the event data. </param>
[__DynamicallyInvokable]
[HostProtection(SecurityAction.LinkDemand, SharedState = true)]
public delegate void PropertyChangedEventHandler(object sender, PropertyChangedEventArgs e);
}
你应该能发现在这个委托上面有一个HostProtection属性,这个属性允许使用声明性安全动作来确定主机保护要求。在这个HostProtectionAttribute : CodeAccessSecurityAttribute 的实现内部,它创建了线程同步锁。以下是它的部分代码:
/// <summary>Gets or sets a value indicating whether synchronization is exposed.</summary>
/// <returns>true if synchronization is exposed; otherwise, false. The default is false.</returns>
public bool Synchronization
{
get
{
return (this.m_resources & HostProtectionResource.Synchronization) > HostProtectionResource.None;
}
set
{
this.m_resources = (value ? (this.m_resources | HostProtectionResource.Synchronization) : (this.m_resources & ~HostProtectionResource.Synchronization));
}
}
/// <summary>Gets or sets a value indicating whether shared state is exposed.</summary>
/// <returns>true if shared state is exposed; otherwise, false. The default is false.</returns>
public bool SharedState
{
get
{
return (this.m_resources & HostProtectionResource.SharedState) > HostProtectionResource.None;
}
set
{
this.m_resources = (value ? (this.m_resources | HostProtectionResource.SharedState) : (this.m_resources & ~HostProtectionResource.SharedState));
}
}
所以对于你的问题:
当使用 UI 线程中的可观察字典时,该对象也必须是线程安全的吗?
如果字典不在 UI 线程上管理怎么办?
在UI线程中,如果你的代码中没有跨线程变量访问是安全的,否则会导致不安全。当不在UI线程中时,我们需要使用invoke方式(UI Dispatcher)将动作推送到UI线程。