新增 FlowScope Git 包雏形
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using FlowScope.Data;
|
||||
|
||||
namespace FlowScope.Save
|
||||
{
|
||||
public interface ISaveSerializer
|
||||
{
|
||||
byte[] Serialize<T>(T data);
|
||||
T Deserialize<T>(byte[] bytes);
|
||||
}
|
||||
|
||||
public sealed class JsonSaveSerializer : ISaveSerializer
|
||||
{
|
||||
private readonly int _currentVersion;
|
||||
private readonly SaveMigrationRegistry _migrations;
|
||||
|
||||
public JsonSaveSerializer(
|
||||
int currentVersion = 1,
|
||||
SaveMigrationRegistry migrations = null)
|
||||
{
|
||||
if (currentVersion < 1)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(currentVersion));
|
||||
}
|
||||
|
||||
_currentVersion = currentVersion;
|
||||
_migrations = migrations ?? new SaveMigrationRegistry();
|
||||
}
|
||||
|
||||
public byte[] Serialize<T>(T data)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(SerializeToString(data));
|
||||
}
|
||||
|
||||
public T Deserialize<T>(byte[] bytes)
|
||||
{
|
||||
if (bytes == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(bytes));
|
||||
}
|
||||
|
||||
return DeserializeFromString<T>(Encoding.UTF8.GetString(bytes));
|
||||
}
|
||||
|
||||
public string SerializeToString<T>(T data)
|
||||
{
|
||||
var payload = ReactivePropertyJsonConverter.SerializeObject(data);
|
||||
if (_currentVersion <= 1)
|
||||
{
|
||||
return payload;
|
||||
}
|
||||
|
||||
return ReactivePropertyJsonConverter.SerializeObject(new SaveEnvelope
|
||||
{
|
||||
Version = _currentVersion,
|
||||
Payload = payload
|
||||
});
|
||||
}
|
||||
|
||||
public T DeserializeFromString<T>(string json)
|
||||
{
|
||||
var instance = (T)Activator.CreateInstance(typeof(T), true);
|
||||
PopulateFromString(ResolvePayload<T>(json), instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void PopulateFromString<T>(string json, T target)
|
||||
{
|
||||
ReactivePropertyJsonConverter.PopulateObject(ResolvePayload<T>(json), target);
|
||||
}
|
||||
|
||||
private string ResolvePayload<T>(string json)
|
||||
{
|
||||
if (!TryReadEnvelope(json, out var envelope))
|
||||
{
|
||||
return _currentVersion > 1
|
||||
? _migrations.Migrate(GetMigrationKey<T>(), 1, _currentVersion, json)
|
||||
: json;
|
||||
}
|
||||
|
||||
if (envelope.Version == _currentVersion)
|
||||
{
|
||||
return envelope.Payload;
|
||||
}
|
||||
|
||||
if (envelope.Version > _currentVersion)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Save version {envelope.Version} is newer than current version {_currentVersion}.");
|
||||
}
|
||||
|
||||
return _migrations.Migrate(
|
||||
GetMigrationKey<T>(),
|
||||
envelope.Version,
|
||||
_currentVersion,
|
||||
envelope.Payload);
|
||||
}
|
||||
|
||||
private static bool TryReadEnvelope(string json, out SaveEnvelope envelope)
|
||||
{
|
||||
envelope = null;
|
||||
try
|
||||
{
|
||||
envelope = ReactivePropertyJsonConverter.DeserializeObject<SaveEnvelope>(json);
|
||||
return envelope.Version > 0 && envelope.Payload != null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetMigrationKey<T>()
|
||||
{
|
||||
return typeof(T).FullName;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user