类型系统
本页包含了运行时可序列化的类型。此外,本页还包含了如何定义自定义可序列化类型和版本兼容性。
可序列化类型
基础类型
Nino支持序列化一切unmanaged type(包括用户自己定义的),也就是说Nino默认支持:
- byte
- short
- enum
- int
- long
- float
- double
- DateTime
- Guid
- Vector
- Matrix
- 非托管struct
- 非托管泛型struct
- 非托管record struct
- 非托管泛型record struct
INFO
Nino 也支持String类型
INFO
只包含unmanaged类型字段的用户自定义struct
、struct<T>
(T
是非托管类型)、record struct
、record struct<T>
(T
是非托管类型)也被视为unmanaged类型(非托管结构体),Nino可以自动将其序列化
对于自定义的非托管结构体,Nino会自动序列化和反序列化结构中的所有字段,序列化和反序列化的顺序由结构中字段的顺序决定(或[StructLayout(LayoutKind.Explicit)]
来指定)。
Nino不支持显式指定要排除哪些字段或在反序列化时使用哪个构造函数
自定义类型
如果需要序列化托管类型(即不是上述类型),请给class
、struct
、record
、record struct
添加[NinoType]
特性,以便Nino生成序列化和反序列化函数,例如:
[NinoType]
public struct SampleStruct
{
public int Id;
public string Name { get; set; }
}
[NinoType]
public record SampleRecord(int Id, string Name);
[NinoType]
public record struct SampleRecordStruct(int Id, string Name);
[NinoType]
public class SampleClass
{
public int Id;
public string Name { get; set; }
}
INFO
[NinoType]
特性默认会收集对应类
或结构体
所有public字段及包含getter与setter的属性。如果是record
或record struct
,则会在此之上收集主要构造函数的参数
若希望手动标记需要序列化的成员请使用[NinoType(false)]
修饰类或结构体并用[NinoMember(id)]
修饰需要序列化的成员(标签内部需要传入一个数字参数,即序列化和反序列化时该成员的位置,收集顺序是按标签的数字从小到大排序的):
[NinoType(false)]
public class SampleClass
{
public int Id;
[NinoMember(1)]
public string Name { get; set; }
}
[NinoType(false)]
public record SampleRecord(
[NinoMember(2)] int Id,
[NinoMember(1)] string Name);
[NinoType(false)]
public record struct SampleRecord(
[NinoMember(2)] int Id,
[NinoMember(1)] string Name);
INFO
如果需要收集非public
成员,如protected
及private
字段,请给NinoType
特性传递额外参数:
[NinoType(containNonPublicMembers: true)]
public class SampleClass
{
private int Id;
}
INFO
如果开启了自动收集全部字段和属性,且需要略过某些字段或属性(如private字段/属性),请将其打上[NinoIgnore]
标签,需要注意的是,如果没开启自动收集,该标签会无效
[NinoType]
public class SampleClass
{
[NinoIgnore]
public int Id;
public string Name { get; set; }
}
WARNING
[NinoIgnore]
不适用 于record的主要构造函数参数,也 不适用 于非托管结构的字段。
泛型类型
Nino支持序列化和反序列化泛型类型,例如:
[NinoType]
public struct GenericStruct<T>
{
public T Val;
}
[NinoType]
public class Generic<T>
{
public T Val;
}
[NinoType]
public record SimpleRecord6<T>(int Id, T Data);
[NinoType]
public record struct SimpleRecordStruct2<T>(int Id, T Data);
INFO
Nino还支持对泛型参数进行约束:
[NinoType]
public class ComplexGeneric<T> where T : IList
{
public T Val;
}
INFO
Nino还支持对使用泛型参数声明的泛型类型成员进行序列化和反序列化,例如:
[NinoType]
public class ComplexGeneric2<T>
{
public Generic<T> Val;
}
WARNING
Nino会在定义泛型实例类型时生成对应的函数,需要确保实例化的泛型参数是可以被序列化的类型,例如:
Generic<int> generic = new Generic<int>();
Generic<string> generic = new Generic<string>();
Generic<List<int>> generic = new Generic<List<int>>();
集合类型
除了支持序列化和反序列化上述类型之外,Nino还支持序列化上述类型的集合类型(包含字典),例如:
List<T>
,T是可序列化类型Dictionary<TKey, TValue>
,TKey和TValue是可序列化类型T[]
,T是可序列化类型ICollection<T>
,T是可序列化类型IDictionary<TKey, TValue>
,TKey和TValue是可序列化类型Span<T>
,T是可序列化类型HashSet<T>
,T是可序列化类型ArraySegment<T>
,T是可序列化类型
WARNING
当定义字典的子类时,必须申明一个公开的索引器,否则不会生成序列化/反序列化代码,例如:
public class MultiMap<T, K> : SortedDictionary<T, List<K>>
{
public new List<K> this[T key]
{
get
{
if (!TryGetValue(key, out List<K> value))
{
value = new List<K>();
Add(key, value);
}
return value;
}
set
{
if (value.Count == 0)
{
Remove(key);
}
else
{
base[key] = value;
}
}
}
}
嵌套类型
Nino支持序列化和反序列化嵌套的可序列化类型,例如:
List<Dictionary<int, SampleStruct>>[]
,SampleStruct是可序列化类型Dictionary<int[], List<bool>[]>
IDictionary<string, IList<List<bool>[]>[]>[]
多态类型
Nino支持序列化和反序列化多态类型,需要注意的是,每个需要序列化的类型(接口、基类或派生类)都需要使用[NinoType]
特性修饰,例如:
[NinoType]
public class BaseClass
{
public int Id;
}
[NinoType]
public class DerivedClass : BaseClass
{
public string Name;
}
当我们把一个DerivedClass
对象转换为BaseClass
对象去序列化时,Nino会自动识别并序列化DerivedClass
的所有字段和属性,反序列化时也会自动转换为DerivedClass
对象
INFO
这样一来我们可以随便序列化一个BaseClass
集合,在反序列化时Nino依然能正常还原出每个元素的真实类型:
var list = new List<BaseClass>
{
new BaseClass { Id = 1 },
new DerivedClass { Id = 2, Name = "Nino" }
};
var bytes = Serializer.Serialize(list);
Deserializer.Deserialize(bytes, out List<BaseClass> result);
// result[0]是BaseClass对象,result[1]是DerivedClass对象
抽象类和接口
Nino支持序列化和反序列化接口和抽象类,需要注意的是接口或抽象类的实现类/结构体需要被[NinoType]
特性修饰(同时接口和抽象类本身也需要被[NinoType]
特性修饰),例如:
[NinoType]
public interface IBase
{
int A { get; set; }
}
[NinoType]
public class Impl : IBase
{
public int A { get; set; }
}
[NinoType]
public struct ImplStruct : IBase
{
public int A { get; set; }
}
[NinoType]
public abstract class Base
{
public int A { get; set; }
}
[NinoType]
public class Derived : Base
{
public int B { get; set; }
}
因为Nino支持多态,所以序列化接口或抽象类的实现类时会自动保留所有元数据,反序列化过程会自动还原对象的真实类型。