异常:DataAnalysis.Reference + <> c__DisplayClass4无法序列化

时间:2019-04-19 08:38:38

标签: c# serialization reflection delegates

我正在程序结尾处尝试序列化类Reference的对象。引发序列化异常,该异常抱怨“ DataAnalysis.Reference + <> c__DisplayClass4”未标记为可序列化。

最初,我有两个没有Serializable属性的代表,因此我尝试了一下,但是没有任何改变。类CacheableOperation已经被标记为Serializable-实际上,在我介绍Reference类之前,这两个类的序列化工作都很好。

我什至不知道c__DisplayClass4是什么意思。因此,很抱歉,但是我不知道将1 MB以上的源代码中的其他部分发布到这里来帮助您解决问题,因为最终我将发布所有内容。

正如我所说,在引入Reference类之前,一切工作正常。因此,我希望问题可以以某种方式局部化。

using System;
using System.Reflection;

namespace DataAnalysis
{
    /// <summary>
    /// Description of Reference.
    /// </summary>
    [Serializable]
    public class Reference
    {
        [Serializable]
        public delegate void ReferenceSetter(Operation op, Cacheable c);

        [Serializable]
        public delegate Cacheable ReferenceGetter(Operation op);

        readonly ReferenceGetter refGetter;
        readonly ReferenceSetter refSetter;

        public Reference(ReferenceGetter getter, ReferenceSetter setter)
        {
            refGetter = getter;
            refSetter = setter;
        }

        public Reference(FieldInfo operationField)
        {
            refGetter = (op => (Cacheable)operationField.GetValue(op));
            refSetter = ((op, value) => operationField.SetValue(op, value));
        }

        public Cacheable this[Operation op]
        {
            get {return refGetter(op);}
            set {refSetter(op, value);}
        }
    }
}

编辑:我选择了taffer的第一个解决方案(避免在委托中使用FieldInfo):

public class Reference
{
    public delegate void ReferenceSetter(Operation op, Cacheable c);
    public delegate Cacheable ReferenceGetter(Operation op);

    readonly FieldInfo opField;
    readonly ReferenceGetter refGetter;
    readonly ReferenceSetter refSetter;

    public Reference(ReferenceGetter getter, ReferenceSetter setter)
    {
        refGetter = getter;
        refSetter = setter;
    }

    public Reference(FieldInfo operationField)
    {
        opField = operationField;
    }

    public Cacheable this[Operation op]
    {
        get 
        {
            if (opField != null) return (Cacheable)opField.GetValue(op);
            else return refGetter(op);
        }
        set 
        {
            if (opField != null) opField.SetValue(op, value);
            else refSetter(op, value);
        }
    }
}

尚未完善,我最终可能会使用具有两个实现的抽象Reference类。但是原理很清楚。

1 个答案:

答案 0 :(得分:1)

由于在第二个构造函数中初始化字段的方式而导致错误:

public Reference(FieldInfo operationField)
{
    // operationField is captured in the lambda below, which causes to generate an inner class
    // where operationField will be a field so can be accessed by the method of the lambda body
    refGetter = (op => (Cacheable)operationField.GetValue(op));
    refSetter = ((op, value) => operationField.SetValue(op, value));
}

解决方案1 ​​

不要在lambda中捕获封闭方法的局部变量和参数。该字段应该是委托的参数。

解决方案2

实施ISerializable并提供自定义序列化:

void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
    info.AddValue("getter", refGetter);
    info.AddValue("setter", refSetter);
}

// the special constructor needed for deserialization
private Reference(SerializationInfo info, StreamingContext context)
{
    refGetter = (ReferenceGetter)info.GetValue("getter", typeof(ReferenceGetter));
    refSetter = (ReferenceSetter)info.GetValue("setter", typeof(ReferenceSetter));
}

请注意,反序列化非静态方法的委托可能会出现问题。如果setter或getter是实例方法,也许应该检查Delegate.Method中的GetObjectData属性并抛出异常。