在反序列化期间,在泛型类内部调用泛型方法的委托将CPU挂起

本文关键字:挂起 CPU 泛型方法 调用 反序列化 泛型类 内部 | 更新日期: 2023-09-27 17:48:49

以前有其他人遇到过这个问题吗?我有一个方法,它在泛型类内部用委托调用泛型方法。我已经将该类标记为Serializable,并且它可以毫无怨言地序列化。但是,当我尝试反序列化此类的对象时,它会挂起CPU并挂起机器。

代码示例:

public delegate T CombinationFunctionDelegate<T,U,V>(U a, V b);
    [Serializable]
public class SDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
    public SDictionary()
        : base()
    {
    }
    protected SDictionary(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {}
    [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        base.GetObjectData(info, context);
    }
    public List<ListItem> ToListItems()
    {
        return Convert(delegate(TKey key, TValue value)
        {
            return new ListItem(key.ToString(), value.ToString());
        });
    }
    public List<U> Convert<U>(CombinationFunctionDelegate<U, TKey, TValue> converterFunction)
    {
        List<U> res = new List<U>();
        foreach (TKey key in Keys)
            res.Add(converterFunction(key, this[key]));
        return res;
    }
}

我可以把这个类的一个实例放入ViewState中(例如),但当我再次尝试从ViewState中提取对象时,机器上的CPU会出现峰值,反序列化调用永远不会返回(即无限循环)。

当我删除ToListItems()方法时,一切都非常好用。这真的很奇怪吗,还是我只是不理解序列化?=)

在反序列化期间,在泛型类内部调用泛型方法的委托将CPU挂起

这是我目前拥有的代码,哪个工作正常?

    [Serializable]
    public class SDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    {
        public SDictionary()
            : base()
        {
        }
        protected SDictionary(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
        }
        public List<ListItem> ToListItems()
        {
            return this.Convert(delegate(TKey key, TValue value)
            {
                return new ListItem(key.ToString(), value.ToString());
            });
        }
        public List<U> Convert<U>(CombinationFunctionDelegate<U, TKey, TValue> converterFunction)
        {
            List<U> res = new List<U>();
            foreach (TKey key in Keys)
                res.Add(converterFunction(key, this[key]));
            return res;
        }

    }
    class Program
    {
        static void Main(string[] args)
        {
            SDictionary<string, string> b = new SDictionary<string, string>();
            b.Add("foo", "bar");
            System.IO.MemoryStream memStream = new System.IO.MemoryStream();
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter f = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            f.Serialize(memStream, b);
            memStream.Position = 0;
            b = f.Deserialize(memStream) as SDictionary<string, string>;
        }
    }

这有帮助吗?

编辑:再次调整。

您使用的是VS2008 SP1吗?SP1存在已知问题。
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=361615

首先,Dictionary<>已经实现了ISerializable,所以不需要指定显式!

其次,您覆盖了GetObjectData(),但似乎没有调用Dictionary.GetObjectData(?因此,当您访问此时。Keys,你最终会遇到"问题"。

是的,我在这里大声思考;)

也许你可以试试这个:

public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
  // deserialize the dictionary first
  base.GetObjectData(info, context);
  // the rest of your code
  // ...
}

我还没有尝试或编译过这个,但它可能是需要考虑的?

祝你好运:)

匿名方法是否引用了它所在的实例?我不能回答。

你的评论表明这是可能的。这里有一个最简单的方法:不要使用匿名方法。

public ListItem ToListItem(TKey key, TValue value)
{
  return new ListItem(key.ToString(), value.ToString());
}

我可以回答的是,这个类上的方法可以根据Dictionary<T、 U>,因此当您可以针对Dictionary<T、 U>(假设C#3)

类似这样的东西(自由手代码,所以可能不是100%正确)

public static List<ListItem> ToListItems(this Dictionary<T, U> source)
{
  return source
    .Select(x => new ListItem(x.key.ToString(), x.value.ToString()))
    .ToList();
}
public static List<V> Convert<V>
(
  this Dictionary<T, U> source,
  Func<T, U, V> converterFunction
)
{
  return source
    .Select(x => converterFunction(x.Key, x.Value))
    .ToList();
}

如果有人需要,这里还有关于这个bug的知识库文章:

在运行Microsoft.NET Framework 3.5 Service Pack 1(SP1)的计算机上,您有一个序列化和反序列化泛型类的应用程序。如果泛型类至少有一个静态成员,您可能会遇到以下症状之一:

  • 如果应用程序作为32位进程运行,则执行反序列化的线程可能会进入循环。因此,应用程序会出现故障,并且会消耗大量的CPU资源
  • 如果应用程序作为64位进程运行,则会引发异常,并且您会收到类似于以下内容的错误消息: