一種方法是表達與反思的組合(我會離開高速緩存作爲一個實現細節):
// Action for a given struct that writes each field to a BinaryWriter
static Action<BinaryWriter, T> CreateWriter<T>()
{
// TODO: cache/validate T is a "simple" struct
var bw = Expression.Parameter(typeof(BinaryWriter), "bw");
var obj = Expression.Parameter(typeof(T), "value");
// I could not determine if .Net for Metro had BlockExpression or not
// and if it does not you'll need a shim that returns a dummy value
// to compose with addition or boolean operations
var body = Expression.Block(
from f in typeof(T).GetTypeInfo().DeclaredFields
select Expression.Call(
bw,
"Write",
Type.EmptyTypes, // Not a generic method
new[] { Expression.Field(obj, f.Name) }));
var action = Expression.Lambda<Action<BinaryWriter, T>>(
body,
new[] { bw, obj });
return action.Compile();
}
使用像這樣:
public static byte[] GetBytes<T>(T value)
{
// TODO: validation and caching as necessary
var writer = CreateWriter(value);
var memory = new MemoryStream();
writer(new BinaryWriter(memory), value);
return memory.ToArray();
}
要讀這回,它涉及多一點:
static MethodInfo[] readers = typeof(BinaryReader).GetTypeInfo()
.DeclaredMethods
.Where(m => m.Name.StartsWith("Read") && !m.GetParameters().Any())
.ToArray();
// Action for a given struct that reads each field from a BinaryReader
static Func<BinaryReader, T> CreateReader<T>()
{
// TODO: cache/validate T is a "simple" struct
var br = Expression.Parameter(typeof(BinaryReader), "br");
var info = typeof(T).GetTypeInfo();
var body = Expression.MemberInit(
Expression.New(typeof(T)),
from f in info.DeclaredFields
select Expression.Bind(
f,
Expression.Call(
br,
readers.Single(m => m.ReturnType == f.FieldType),
Type.EmptyTypes, // Not a generic method
new Expression[0]));
var function = Expression.Lambda<Func<BinaryReader, T>>(
body,
new[] { br });
return function.Compile();
}
是二進制序列化的圖片嗎?另一個問題是,如果表現很重要,那麼涉及'AllocHGlobal'似乎很奇怪。 – user7116
關於每次調用使用AllocHGlobal的好處。爲了提高效率,我的實際執行情況稍微複雜一點。它緩存len,arr和ptr,以便每次轉換爲字節的實際調用只涉及Marshal.StructureToPtr和Marshal.Copy。發佈的代碼只是一個簡單的例子。 –
我用二進制序列化的問題是開銷。具有單個int32字段的結構將被序列化爲140字節。如果你的結構相當大,那麼這個開銷並不大,但在我的情況下,我有很多相對較小的對象。所以將結構轉換爲它包含的實際4字節對我來說是一個很大的節約。 –