c# - Exception: DataAnalysis.Reference+<>c__DisplayClass4 is not serializable
问题描述
I am trying to serialize objects of class Reference
at the end of my program. A serialization exception is thrown, which complains that "DataAnalysis.Reference+<>c__DisplayClass4" is not marked as serializable.
Initially I had the two delegates without the Serializable
attribute, so I gave it a try, but it didn't change anything. The classes Cacheable
and Operation
are already marked as Serializable
- and in fact the serialization of the both of them worked perfectly fine before I introduced the Reference
class.
I don't even know what c__DisplayClass4 means. So I am sorry, but I don't know what other parts of my 1 megabytes+ source code to post here to help you solve the problem, because in the end I would be posting everything.
As I said, everything worked fine before introducing the Reference
class. So I am hoping the problem is somehow localized to it.
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);}
}
}
}
Edit: I have chosen taffer's first solution (avoid using the FieldInfo inside a delegate):
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);
}
}
}
Not polished yet, I will probably finally use an abstract Reference
class with two implementations. But the principle becomes clear.
解决方案
You get the error because of the way you initialize your fields in the second constructor:
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));
}
Solution 1:
Do not capture locals and parameters of the enclosing method in the lambda. The field should rather be a parameter of the delegate.
Solution2:
Implement ISerializable
and provide a custom serialization:
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));
}
Please note that deserializing delegates of non-static methods can be problematic. Maybe you should check the Delegate.Method
property in GetObjectData
and throw an exception if the setter or getter is an instance method.
推荐阅读
- php - 前导 0 的月份从 createfromformat 得到错误结果
- r - 有没有一种快速的方法来提取与今天日期相对应的几年内的数据
- javascript - TypeError:无法读取 javascript 中检查的 null 错误的属性“已检查”
- bash - 使用 awk 通过几列与文件相交
- pandas - 如何计算一系列 Point 对象和一系列 Polygon 对象之间的距离?
- laravel - 如何更改 laravel 背包中列表字段的类型?
- docker - 如何根据规模 id 动态绑定 docker 卷?
- python - 使用 python 函数替换特定列中的字符然后抛出 TypeError: cannot convert the series to
- php - 无法通过 PHP 将图像文件上传到 S3 存储桶
- python - 无法在俄语/乌克兰语中解码 Python 错误