我有一个拥有通用列表的类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());
}
当我在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&lt;&gt; (?!)
当我尝试通过WCF服务发回此对象时,我得到日志输出
OnSerializing of Team called
XXX.Person[]
在此之后,我的单元测试因System.ExecutionEngineException崩溃,这意味着WCF服务无法序列化数组。 (也许是因为它期望IList&lt;&gt;)
所以,我的问题是:有人知道为什么我的IList的类型&lt;&gt;反序列化后是一个数组,为什么我不能在那之后再序列化我的Team对象?
由于
答案 0 :(得分:22)
你遇到了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<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怪癖。
答案 1 :(得分: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
答案 2 :(得分:1)
听起来您的WCF服务引用正在创建代理类而不是使用现有类型。代理类只能使用简单数组,而不能使用任何.NET特定类型,如通用List。
要避免此代理类转换,请在“添加服务引用”屏幕中单击“高级”按钮,然后确保选中“在引用的程序集中重用类型”。这将确保在序列化和反序列化对象时使用现有类(使用通用List)。
答案 3 :(得分:1)
直接从我的博客中摘录。我希望它会有所帮助:
我最近遇到了一个问题,我们在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;
}