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

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

[DataContract(Name = "TeamDTO", IsReference = true)] public class Team { [DataMember] private IList members = new List(); public Team() { Init(); } private void Init() { members = new List(); } [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[] 

在此之后,我的unit testing与System.ExecutionEngineException崩溃,这意味着WCF服务无法序列化该数组。 (也许是因为它期待一个IList )

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

谢谢

你遇到了一个DataContractSerializer陷阱。

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

 [DataMember] private List members = new List(); 

或者将属性更改为:

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

它会工作。 Microsoft Connect错误在这里

使用IList 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: {0}", values is IList); } } 

它将打印int[] is IList: True

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

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

其中一个.NET怪癖。

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

应用程序池崩溃,没有任何警告。

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

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

分辨率是安装MS修补程序KB973110 http://support.microsoft.com/kb/971030/en-us

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

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

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

我最近遇到了一个问题,我们在ASP.net MVC应用程序中使用WCF服务并使用自定义模型绑定器。 当我们序列化我们的IList时,一切都工作得很好。 IList默认情况下会序列化为数组。 我最终使用Reflection将数组转换回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; }