WCF:序列化和反序列化通用集合

Fab*_*ano 20 .net c# wcf serialization generic-list

我有一个拥有通用列表的类Team:

[DataContract(Name = "TeamDTO", IsReference = true)]
public class Team
{
    [DataMember]
    private IList<Person> members = new List<Person>();

    public Team()
    {
        Init();
    }

    private void Init()
    {
        members = new List<Person>();
    }

    [System.Runtime.Serialization.OnDeserializing]
    protected void OnDeserializing(StreamingContext ctx)
    {
        Log("OnDeserializing of Team called");
        Init();
        if (members != null) Log(members.ToString());
    }

    [System.Runtime.Serialization.OnSerializing]
    private void OnSerializing(StreamingContext ctx)
    {
        Log("OnSerializing of Team called");
        if (members != null) Log(members.ToString());
    }

    [System.Runtime.Serialization.OnDeserialized]
    protected void OnDeserialized(StreamingContext ctx)
    {
        Log("OnDeserialized of Team called");
        if (members != null) Log(members.ToString());
    }

    [System.Runtime.Serialization.OnSerialized]
    private void OnSerialized(StreamingContext ctx)
    {
        Log("OnSerialized of Team called");
        Log(members.ToString());
    }
Run Code Online (Sandbox Code Playgroud)

当我在WCF服务中使用此类时,我得到以下日志输出

OnSerializing of Team called    
System.Collections.Generic.List 1[XXX.Person]

OnSerialized of Team called    
System.Collections.Generic.List 1[XXX.Person]

OnDeserializing of Team called    
System.Collections.Generic.List 1[XXX.Person]

OnDeserialized of Team called    
XXX.Person[]
Run Code Online (Sandbox Code Playgroud)

反序列化后members是一个数组而不再是通用列表,虽然字段类型是IList <>(?!)当我尝试通过WCF服务发回这个对象时,我得到了日志输出

OnSerializing of Team called
XXX.Person[]
Run Code Online (Sandbox Code Playgroud)

在此之后,我的单元测试崩溃了System.ExecutionEngineException,这意味着WCF服务无法序列化数组.(也许是因为它期待一个IList <>)

所以,我的问题是:有人知道为什么我的IList <>的类型在反序列化之后是一个数组,为什么我不能在那之后序列化我的Team对象?

谢谢

Leo*_*edt 22

你遇到了其中一个DataContractSerializer陷阱.

修复:将您的私有成员声明更改为:

[DataMember]
private List<Person> members = new List<Person>();
Run Code Online (Sandbox Code Playgroud)

或者将属性更改为:

[DataMember()]
public IList<Person> Feedback {
    get { return m_Feedback; }
    set {
        if ((value != null)) {
            m_Feedback = new List<Person>(value);

        } else {
            m_Feedback = new List<Person>();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它会奏效.Microsoft Connect错误在这里

使用IList<T>DataMember 反序列化对象,然后再次尝试序列化同一实例时,会发生此问题.

如果你想看到一些很酷的东西:

using System;
using System.Collections.Generic;

class TestArrayAncestry
{
    static void Main(string[] args)
    {
        int[] values = new[] { 1, 2, 3 };        
        Console.WriteLine("int[] is IList<int>: {0}", values is IList<int>);
    }
}
Run Code Online (Sandbox Code Playgroud)

它会打印出来int[] is IList<int>: True.

我怀疑这可能是你看到它在反序列化后作为数组返回的原因,但它非常不直观.

如果你IList<int>在数组上调用Add()方法,它会抛出NotSupportedException.

其中一个.NET怪癖.

  • 谢谢.这真的很难找出"我"会影响什么.同时我找到了另一个解决方案,特别是当你需要一个IList <>而不是List <>时(例如我的OR-Mapper只能处理IList <>而不是List <>):而不是用[标记"成员"字段[ DataMember]标记属性并将此代码用于setter:if(value!= null)members = new List <Person>(value); else members = new List <Person>(); 这样,反序列化的数组就会传递给setter,从而从中创建一个新的List. (3认同)