按需创建同步对象

时间:2017-01-13 07:38:12

标签: c# .net synchronization

我有一个包含Sync对象的类

[DataContract]
class C1
{
  [DataMember]
  private object mySyncObject = new object();
}

此对象以前是DataContract的一部分,它是由于没有明显原因而序列化的。由于它不包含任何数据,因此我在同步对象上省略了DataMember。但是由于DataContractSerializer在反序列化期间不会调用默认的ctor,因此当我使用它时会在运行时导致NullReferenceExceptions。

lock(mySyncObject) // NullReferenceException

现在我想在属性中封装锁对象访问,并确保多线程访问不会导致该属性返回null或不同的对象。

我修改后的对象现在看起来像

[DataContract]
class C1
{
    private volatile object mySyncObject = new object();

    object SyncObject
    {
        get
        {
            if (mySyncObject == null)
            {
                Interlocked.CompareExchange<object>(ref mySyncObject, new object(), null);
            }
            return mySyncObject;
        }
    }
}

可以这么容易,还是我错过了潜在的竞争条件?

1 个答案:

答案 0 :(得分:1)

由于Interlock.CompareExchange<T>(ref T location1, T value, T comparand)atomic operation,您还没有错过潜在的竞争条件。您宁愿创建与Lazy<T>实现类似的实现。

可以在这个blog上找到一个很好的例子来讨论你正在展示的非常类似的实现(因此,我也不会再次添加实现)。



原始答案,替代OP建议实施

作为替代方案,您也可以在反序列化后使用OnDeserializedAttribute初始化mySyncObject,如下例所示

[DataContract]
class C1 
{
    private object mySyncObject = new object();

    [OnDeserialized]
    internal void OnDeserialized(StreamingContext context)
    {
        mySyncObject = new object();
    }
}

通过这种方式,您可以在任何地方保留原始逻辑,并且在反序列化发生后直接调用该方法,并初始化您的mySyncObject。

正如我们在评论中所讨论的那样,这与DataContractSerializerBinaryFormatterJSON.Net兼容。

有关DataContractSerializer未使用默认构造函数的原因的详细信息,请参阅此answer