19

我有一个包含通用列表的班级团队:

[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());
    }

当我在 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[]

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

OnSerializing of Team called
XXX.Person[]

在此之后,我的单元测试因 System.ExecutionEngineException 而崩溃,这意味着 WCF 服务无法序列化数组。(可能是因为它需要一个 IList<>)

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

谢谢

4

4 回答 4

21

您遇到了其中一个问题DataContractSerializer

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

[DataMember]
private List<Person> members = new List<Person>();

或将属性更改为:

[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>();
        }
    }
}

它会起作用。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>);
    }
}

它将打印int[] is IList<int>: True.

我怀疑这可能是您在反序列化后看到它以数组形式返回的原因,但这很不直观。

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

这些 .NET 怪癖之一。

于 2010-04-05T08:48:17.553 回答
2

通过 LINQ 传输从数据库读取的 IList 时出现此错误。WCF 托管在 Windows Server 2008 x64 上的 IIS 7 中。

应用程序池在没有任何警告的情况下崩溃。

[ServiceBehavior]
public class Webservice : IWebservice
{

    public IList<object> GetObjects()
    {
        return Database.Instance.GetObjects();
    }
}

它不完全相同的问题,但可能有相同的原因。

解决方案是安装 MS 修补程序 KB973110 http://support.microsoft.com/kb/971030/en-us

于 2010-08-26T09:25:15.360 回答
1

听起来您的 WCF 服务引用正在创建代理类而不是使用现有类型。代理类只能使用简单的数组,而不能使用任何 .NET 特定类型,如泛型 List。

要避免这种代理类转换,请在“添加服务引用”屏幕中单击“高级”按钮,然后确保选中“在引用的程序集中重用类型”。这将确保在序列化和反序列化对象时使用现有类(具有通用列表)。

于 2010-04-01T16:57:42.487 回答
1

直接取自我的博客。我希望它会有所帮助:

我最近遇到了一个问题,我们正在使用 WCF 服务并在我们的 ASP.net MVC 应用程序中使用自定义模型绑定器。当我们序列化我们的 IList 时,一切都运行良好。IList 默认被序列化为数组。我最终使用反射将我们的数组转换回 ILists 并在自定义模型绑定器中调用以下方法。这是方法的样子:

public object ConvertArraysToIList(object returnObj)    
{

if (returnObj != null)
{
    var allProps = returnObj.GetType().GetProperties().Where(p => p.PropertyType.IsPublic 
        && p.PropertyType.IsGenericType 
        && p.PropertyType.Name==typeof(IList<>).Name).ToList();

    foreach (var prop in allProps)
    {
        var value = prop.GetValue(returnObj,null);
        //set the current property to a new instance of the IList<>
        var arr=(System.Array)value; 
        Type listType=null;

        if(arr!=null)
        {
            listType= arr.GetType().GetElementType();
        }

        //create an empty list of the specific type
        var listInstance = typeof(List<>)
          .MakeGenericType(listType)
          .GetConstructor(Type.EmptyTypes)
          .Invoke(null);

        foreach (var currentValue in arr)
        {
            listInstance.GetType().GetMethod("Add").Invoke(listInstance, new[] { currentValue });
        }

        prop.SetValue(returnObj, listInstance, null);
    }
}

return returnObj;
}
于 2012-05-18T16:01:44.780 回答