【问题标题】:WCF: Serializing and Deserializing generic collectionsWCF:序列化和反序列化泛型集合
【发布时间】:2010-04-01 16:49:39
【问题描述】:

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

[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 对象?

谢谢

【问题讨论】:

    标签: c# .net wcf serialization generic-list


    【解决方案1】:

    您遇到了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 错误是here

    当您使用 IList&lt;T&gt; 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&lt;int&gt;: True

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

    如果你在数组的 IList&lt;int&gt; 上调用 Add() 方法,它会抛出 NotSupportedException

    其中一个 .NET 怪癖。

    【讨论】:

    • 谢谢。这真的很难找出“我”能影响什么。与此同时,我找到了另一个解决方案,特别是当您需要 IList 而不是 List 时(例如,我的 OR-Mapper 只能处理 IList 但不能处理 List):而不是用 [ 标记“成员”字段DataMember] 标记属性并将此代码用于设置器: if (value != null) members = new List(value);其他成员 = 新列表();有了这个,反序列化的数组被传递给 setter,它从中创建一个新的 List。
    • 后一种技术也是我一直在做的。该成员字段不是序列化程序应该触及的东西。
    • 我支持属性方法!我很伤心,因为我自己没有想到。
    【解决方案2】:

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

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

    [ServiceBehavior]
    public class Webservice : IWebservice
    {
    
        public IList<object> GetObjects()
        {
            return Database.Instance.GetObjects();
        }
    }
    

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

    解决方法是安装MS hotfix KB973110 http://support.microsoft.com/kb/971030/en-us

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      • 我在这里不使用服务参考。我参考了我的 WCF 项目,并以编程方式创建了主机和频道。所以,我自己重用了这些类型
      • 我明白了。那么在那种情况下,我不知道。 ;-)
      【解决方案4】:

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

      我最近遇到了一个问题,我们在 ASP.net MVC 应用程序中使用 WCF 服务并使用自定义模型绑定器。当我们序列化我们的 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;
      }
      

      【讨论】:

        猜你喜欢
        • 2017-01-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-04
        • 2020-02-24
        • 2010-10-14
        • 1970-01-01
        相关资源
        最近更新 更多