gpt4 book ai didi

c# - BinaryFormatter 不会反序列化 IEnumerable 上的对象

转载 作者:行者123 更新时间:2023-11-30 23:18:55 25 4
gpt4 key购买 nike

我有这个接口(interface)和类(您可以查看 here 以查看所有相关代码都是可编译的)。我将只提供最少的代码来描述问题(不可编译的代码):

interface IViz<T> : ISerializable {
IEnumerable<SelectedValue> SelectedValues { get; }
};

[Serializable]
abstract class GroupViz<T, TIn, TOut> : IViz<T> {
public IEnumerable<SelectedValue> SelectedValues
{
get { return selectedValues.Cast<SelectedValue>(); }
}
}

[Serializable]
public class EntityValueGroupViz<TEntity, TKey> : ValueGroupViz<TEntity, TKey>

在第一个界面(IViz)我声明了一个属性IEnumerable<SelectedValue> SelectedValues每个 SelectedValue 存储在哪里对象。

SelectedValue有两个实现(通用的和非通用的):

[Serializable]
public abstract class SelectedValue : ISerializable
{
public SelectedValue(SerializationInfo info, StreamingContext context)
{
Configuration.SerializationTemplatesEnum serializationTemplateEnum = (Configuration.SerializationTemplatesEnum)context.Context;

foreach (SerializationEntry entry in info)
{
switch (serializationTemplateEnum)
{
case Configuration.SerializationTemplatesEnum.QUERY:
switch (entry.Name)
{
case "Value":
Value = entry.Value;
break;

case "Operator":
Operator = (VizOperatorEnum)entry.Value;
break;
}
break;

case Configuration.SerializationTemplatesEnum.TEMPLATE:
break;

}

}

}
}

[Serializable]
public class SelectedValue<T> : SelectedValue, ISerializable
{
public SelectedValue(SerializationInfo info, StreamingContext context)
: base(info, context)
{

}
}

我正在使用 BinaryFormatter为了序列化它们,它们(SelectedValue 属性上的 IViz.SelectValues 对象)在文件中被序列化。

但是,当我尝试反序列化它们时,它们没有被加载。我在 SelectedValue(SerializationInfo info, StreamingContext context) 上添加了一个断点构造函数,但未达到。

我还尝试添加一个 set;IViz.SelectedValues 上实现属性,我还尝试将属性设置为 IList而不是 IEnumerable .但是结果是一样的:我的 SelectedValue对象未反序列化。

有什么想法吗?

最佳答案

我能够通过构建 EntityValueGroupViz<BOEntity, BOEntity> 的实例重现您的问题, 添加 SelectedValue<BOEntity>(new BOEntity(), "hello")到它,并序列化。参见 this fiddle对于 mcve .

但是,为了重现问题,我必须:

  • 标记 BOEntity作为[Serializable] .

  • 将默认和流式构造函数添加到 GroupViz<T, TIn, TOut>ValueGroupViz<T, TIn> .

  • 分配 selectedValues列表里面GroupViz<T, TIn, TOut>在构造函数中。

  • 将默认构造函数添加到 EntityValueGroupViz<TEntity, TKey> .

一旦完成这些初步修复,问题就会在 EntityValueGroupViz<TEntity, TKey> 的流式构造函数中变得明显。 :

    protected EntityValueGroupViz(SerializationInfo info, StreamingContext context)
{
foreach (SerializationEntry entry in info)
{
switch (entry.Name)
{
case "SelectedValues":
foreach (SelectedValue sv in (IEnumerable<SelectedValue>)entry.Value)
this.Value(sv);
break;
}
}
}

调用时,(IEnumerable<SelectedValue>)entry.Value有空条目。但是,这是为什么呢? BinaryFormatter是一个图形序列化器。对象不是存储在纯树中,而是分配临时对象 ID 并在遇到时存储。当一个对象被反序列化时,不能保证所有引用的对象之前都被反序列化过。因此,您的 entry.Value 中的条目可能在调用流式构造函数时尚未填写。作为确认,Microsoft writes

Objects are reconstructed from the inside out, and calling methods during deserialization can have undesirable side effects, since the methods called might refer to object references that have not been deserialized by the time the call is made.

遍历 List<T>实际上确实涉及调用它的方法。

那么,如何处理呢?有几个可能的解决方法:

  1. 实现 IDeserializationCallback EntityValueGroupViz<TEntity, TKey> , 暂时缓存 entry.Value在流式构造函数中,稍后将其添加到 IDeserializationCallback.OnDeserialization() 中的基类中:

    [Serializable]
    public class EntityValueGroupViz<TEntity, TKey> : ValueGroupViz<TEntity, TKey>, IDeserializationCallback
    {
    IEnumerable<SelectedValue> cachedEntry;

    // Added necessary default constructor.
    public EntityValueGroupViz() : base() { }

    protected EntityValueGroupViz(SerializationInfo info, StreamingContext context) : base(info, context)
    {
    foreach (SerializationEntry entry in info)
    {
    switch (entry.Name)
    {
    case "SelectedValues":
    cachedEntry = (IEnumerable<SelectedValue>)entry.Value;
    break;
    }
    }
    }

    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
    info.AddValue("SelectedValues", SelectedValues);
    }

    #region IDeserializationCallback Members

    public void OnDeserialization(object sender)
    {
    if (cachedEntry != null)
    {
    foreach (SelectedValue sv in cachedEntry)
    this.Value(sv);
    cachedEntry = null;
    }
    }

    #endregion
    }

    样本 fiddle .

  2. 简单地在字段存在的基类中序列化选定值的列表。 BinaryFormatter序列化流是完全类型化的,所以 selectedValues即使基类不知道集合中的子类型,字段也可以存储在那里:

    [Serializable]
    public abstract class GroupViz<T, TIn, TOut> : IViz<T>
    {
    // Added necessary default and streaming constructors
    public GroupViz()
    {
    selectedValues = new List<SelectedValue>();
    }

    protected GroupViz(SerializationInfo info, StreamingContext context)
    {
    selectedValues = (IList<SelectedValue>)info.GetValue("SelectedValues", typeof(IList<SelectedValue>));
    }

    // Allocated the list
    private IList<SelectedValue> selectedValues;

    public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
    {
    info.AddValue("SelectedValues", selectedValues);
    }

    public IEnumerable<SelectedValue> SelectedValues
    {
    get { return selectedValues.Cast<SelectedValue>(); }
    }

    public void Value(SelectedValue @value)
    {
    this.AddValue(@value.Value, @value.Operator);
    }

    private void AddValue(object @value, object vizOperator)
    {
    SelectedValue<TOut> selectedValue = new SelectedValue<TOut>((TOut)value, vizOperator);
    if (!this.selectedValues.Any(sv => sv.Equals(selectedValue)))
    this.selectedValues.Add(selectedValue);
    }
    }

    public abstract class ValueGroupViz<T, TIn> : GroupViz<T, TIn, TIn>
    {
    // Added necessary default and streaming constructors
    public ValueGroupViz() : base() { }

    protected ValueGroupViz(SerializationInfo info, StreamingContext context) : base(info, context) { }
    }

    [Serializable]
    public class EntityValueGroupViz<TEntity, TKey> : ValueGroupViz<TEntity, TKey>
    {
    // Added necessary default constructor.
    public EntityValueGroupViz() : base() { }

    protected EntityValueGroupViz(SerializationInfo info, StreamingContext context) : base(info, context) { }
    }

    如您所见,此解决方案更简单,因此值得推荐。

    样本 fiddle #2 .

关于c# - BinaryFormatter 不会反序列化 IEnumerable 上的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40549392/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com