实现INotifyPropertyChanged的IDictionary实现必须是线程安全的吗?

时间:2017-11-07 16:59:43

标签: multithreading xamarin.ios xamarin.android inotifypropertychanged concurrentdictionary

我正在查看this code我希望与Xamarin.iOS / Android一起使用的可观察词典。有评论和答案表明并发性并不是一个问题。

一般来说,在处理实现INotifyPropertyChanged的对象时,我应该依赖什么线程安全保证?

换句话说,

  • 当使用UI线程中的可观察字典时,该对象是否也必须是线程安全的?

  • 如果在UI线程上没有管理字典怎么办?

我正在考虑替代实施

1 个答案:

答案 0 :(得分:1)

  

一般来说,在处理实现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线程。