【问题标题】:DataContractSerializer and immutable types. Deserialising to a known object instanceDataContractSerializer 和不可变类型。反序列化为已知对象实例
【发布时间】:2012-04-23 16:19:20
【问题描述】:

我有一个类实际上是一个基于对象的枚举。该类公开了一组静态对象,并且所有内容都使用这些相同的实例。例如(注意私有构造函数)

[DataContract]
public class FieldType
{
    public static readonly FieldType Default  = new FieldType(1, "Default");
    public static readonly FieldType Name     = new FieldType(2, "Name");
    public static readonly FieldType Etc      = new FieldType(3, "Etc");

    private FieldType(uint id, string name)
    {
        Id = id;
        Name = name;
    }

    [DataMember] public uint   Id   { get; private set; }
    [DataMember] public string Name { get; private set; }
    //snip other properties
}

在我必须跨 WCF 序列化之前,这很有效。 DataContractSerializer 通过绕过构造函数创建新对象。这会产生一个有效的FieldType 对象,但它是一个新实例,不是我的静态实例之一。这会导致与已知静态值的引用比较失败。

有什么方法可以覆盖类的序列化行为,以便我创建对象实例而不是填充提供给我的实例?

【问题讨论】:

  • (注意Name用于静态和非静态,意思是:它不会按原样编译)
  • 糟糕,是的。我对这个问题进行了清理并选择了一个坏名字。

标签: c# wcf serialization immutability datacontractserializer


【解决方案1】:

我建议您覆盖EqualsGetHashcode(以及==!=),以便您对静态对象与WCF 创建的对象进行相等性检查。

数据传输对象 (DTO) 不适用于面向对象的行为,它们是纯粹的状态类。但我能理解你面临的问题。

当您的域对象与上面的类一起工作时,或者使用不同的 DTO 发送数据。

【讨论】:

  • 另外,== / != 运算符会很有用,如果它代表一个对象枚举
  • 谢谢。是的,我很可能最终会走这条路。为了简单起见,我只是想保留它以供参考比较(而且因为我很懒)。
【解决方案2】:

怀疑你可以这样做:

[DataContract]
public class FieldType : IObjectReference
{
    object IObjectReference.GetRealObject(StreamingContext ctx)
        switch(Id) {
            case 1: return Default;
            case 2: return Name; // note this is a collision between static/non-static
            case 3: return Etc;
            default: throw new InvalidOperationException();
        }
    }
    public static readonly FieldType Default  = new FieldType(1, "Default");
    // note this is a collision between static/non-static
    public static readonly FieldType Name     = new FieldType(2, "Name");
    public static readonly FieldType Etc      = new FieldType(3, "Etc");

    private FieldType(uint id, string name)
    {
        Id = id;
        Name = name; // note this is a collision between static/non-static
    }

    [DataMember] public uint   Id   { get; private set; }
    // note this is a collision between static/non-static
    [DataMember] public string Name { get; private set; }
    //snip other properties
}

已验证:

public static class Program
{
    static void Main()
    {
        var obj = FieldType.Default;

        using(var ms = new MemoryStream())
        {
            var ser = new DataContractSerializer(typeof (FieldType));
            ser.WriteObject(ms, obj);
            ms.Position = 0;
            var obj2 = ser.ReadObject(ms);

            bool pass = ReferenceEquals(obj, obj2); // true
        }
    }
}

但是请注意,如果我们只使用 Id 来识别要使用的真实对象,那么序列化 Name 似乎没什么意义。

【讨论】:

  • 这看起来很完美,谢谢! (是的,不需要名称。从我幼稚的沼泽标准 WCF 实现中仍然存在)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多