如何将空值自定义反序列化为C#Nullable<;T>;使用二进制格式化程序?

如何将空值自定义反序列化为C#Nullable<;T>;使用二进制格式化程序?,c#,.net,serialization,nullable,binaryformatter,C#,.net,Serialization,Nullable,Binaryformatter,我有一个旧的遗留类型,它的功能基本上与C#2.0中引入的C#nullable相同。我有旧的持久化数据,其中包含用二进制格式化程序序列化的遗留类型。我想完全删除遗留类型(并用C#nullable替换),并在持久化数据的反序列化过程中处理所有必需的类型转换 我几乎成功地使用序列化绑定和代理实现了这一点。然而。我不知道如何让我的遗留空值反序列化为C#nullable类型的正确空值,而不是获取空值,我得到的是底层(非nullable)类型的未初始化对象 下面的示例将打印以下内容,但我希望最后一行为nul

我有一个旧的遗留类型,它的功能基本上与C#2.0中引入的C#nullable相同。我有旧的持久化数据,其中包含用二进制格式化程序序列化的遗留类型。我想完全删除遗留类型(并用C#nullable替换),并在持久化数据的反序列化过程中处理所有必需的类型转换

我几乎成功地使用序列化绑定和代理实现了这一点。然而。我不知道如何让我的遗留空值反序列化为C#nullable类型的正确空值,而不是获取空值,我得到的是底层(非nullable)类型的未初始化对象

下面的示例将打印以下内容,但我希望最后一行为null而不是0:

Before serialization: 17
Before serialization: <null>
After serialization: 17
After serialization: 0
序列化之前的
:17
序列化之前:
序列化后:17
序列化后:0
在下面的示例中,我要替换的类型是NullableInt,它充当非NullableInt类的包装器(后者用于创建强类型整数,但这对我的问题并不重要)

使用系统;
使用System.IO;
使用System.Linq;
使用System.Runtime.Serialization;
使用System.Runtime.Serialization.Formatters.Binary;
命名空间控制台应用程序7{
/// 
///不可为null的类型化整数。我们使用它们来创建强类型
///使具有不同属性的整数更难混合
///目的(比如把Int和Int混为一谈)。
/// 
[可序列化]
内部结构Int{
公共内部;
公共内部(内部内部内部){
这个。内=内;
}
}
/// 
///用作类型化整数的泛型类型参数
/// 
内部结构{
}
/// 
///可为null的类型化整数。这是我想要的旧类型
///替换为C#nullable,即Int?
/// 
[可序列化]
内部结构NullableInt{
私有客体内部;
public static NullableInt Null=新的NullableInt();
公共Int值{get{返回新Int((Int)inner);}
公共bool IsNull{get{return(inner==null);}
公共NullableInt(Int值){
this.inner=value.inner;
}
}
/// 
///反序列化期间使用的SerializationBinder。它将映射旧版
///将类型转换为C#可为null的类型。
/// 
内部类绑定器:SerializationBinder{
公共重写类型BindToType(字符串assemblyName、字符串typeName){
if(typeName==typeof(NullableInt.FullName){
返回类型(Int?);
}否则{
抛出新的NotSupportedException();
}
}
}
/// 
///序列化代理转换旧二进制格式
///从NullableInt到C#nullable
/// 
内部类代理:ISerializationSubrogate{
公共对象SetObjectData(对象对象对象、序列化信息、StreamingContext上下文、iUrrogateSelector选择器){
//获取由NullableInt序列化的对象
对象内部=info.GetValue(“内部”,typeof(对象));
//总是返回Int?
Int?nullable=(inner==null)?(Int?)null:新的Int((Int)inner);
返回可为空;
}
public void GetObjectData(对象对象对象、序列化信息、StreamingContext上下文){
抛出新的NotImplementedException();
}
}
/// 
///主程序测试序列化和反序列化
/// 
班级计划{
静态void Main(字符串[]参数){
//创建要序列化的数据
var data=new NullableInt[2]{
新的NullableInt(新的Int(17)),
NullableInt.Null
};
data.ToList().ForEach(x=>Console.WriteLine(
序列化之前:“+(x.IsNull?”:x.Value.internal.ToString());
//序列化到内存流中
var formatter=新的二进制格式化程序();
var ms=新内存流();
格式化程序。序列化(ms、数据);
//设置用于反序列化的绑定器
格式化程序=新的二进制格式化程序();
formatter.Binder=新的Binder();
//设置反序列化的代理
var progatetselector=新的progatetselector();
代理选择程序。添加代理(
类型(Int),
新StreamingContext(StreamingContextState.All),
新代理项());
代理选择程序。添加代理(
类型(Int?),
新StreamingContext(StreamingContextState.All),
新代理项());
formatter.SurrogateSelector=代理选择器;
//反序列化
Seek女士(0,SeekOrigin.Begin);
var反序列化=(Int?[])格式化程序。反序列化(ms);
反序列化的.ToList().ForEach(x=>Console.WriteLine(
序列化后:“+(x.HasValue?x.Value.internal.ToString():”);
}
}
}
请注意,在最后我得到了一个null值数组,最后一个数组不是null(而是一个内部值为0的未初始化Int)

另外两项意见:

  • 如果删除第一个代理项,即第一次调用AddSubrogate,则根本不会调用ISerializationSubrogate
  • 如果删除第二个代理,则会调用ISerializationSubrogate,但SerializationInfo参数始终设置为null
  • 有人知道从序列化代理返回什么来使二进制格式化程序返回空值而不是未初始化的值吗?或者有没有其他方法来做我想做的事?我也尝试过实现IObjectReference接口,但是