mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-07-09 02:16:55 +00:00
Do the same for serializers
This commit is contained in:
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using SabreTools.Serialization.Interfaces;
|
||||
|
||||
namespace SabreTools.Serialization.Serializers
|
||||
@@ -9,7 +7,10 @@ namespace SabreTools.Serialization.Serializers
|
||||
/// Base class for all binary serializers
|
||||
/// </summary>
|
||||
/// <typeparam name="TModel">Type of the model to serialize</typeparam>
|
||||
/// <remarks>These methods assume there is a concrete implementation of the serializer for the model available</remarks>
|
||||
/// <remarks>
|
||||
/// This class allows all inheriting types to only implement <see cref="IStreamSerializer<>"/>
|
||||
/// and still implicitly implement <see cref="IByteSerializer<>"/> and <see cref="IFileSerializer<>"/>
|
||||
/// </remarks>
|
||||
public abstract class BaseBinarySerializer<TModel> :
|
||||
IByteSerializer<TModel>,
|
||||
IFileSerializer<TModel>,
|
||||
@@ -20,7 +21,7 @@ namespace SabreTools.Serialization.Serializers
|
||||
/// <inheritdoc/>
|
||||
public virtual byte[]? SerializeArray(TModel? obj)
|
||||
{
|
||||
using var stream = SerializeStream(obj);
|
||||
using var stream = Serialize(obj);
|
||||
if (stream == null)
|
||||
return null;
|
||||
|
||||
@@ -39,7 +40,7 @@ namespace SabreTools.Serialization.Serializers
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return false;
|
||||
|
||||
using var stream = SerializeStream(obj);
|
||||
using var stream = Serialize(obj);
|
||||
if (stream == null)
|
||||
return false;
|
||||
|
||||
@@ -56,110 +57,5 @@ namespace SabreTools.Serialization.Serializers
|
||||
public abstract Stream? Serialize(TModel? obj);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Static Implementations
|
||||
|
||||
/// <inheritdoc cref="IByteSerializer.Deserialize(T?)"/>
|
||||
public static byte[]? SerializeBytes(TModel? obj)
|
||||
{
|
||||
var serializer = GetType<IByteSerializer<TModel>>();
|
||||
if (serializer == null)
|
||||
return default;
|
||||
|
||||
return serializer.SerializeArray(obj);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IFileSerializer.Serialize(T?, string?)"/>
|
||||
public static bool SerializeFile(TModel? obj, string? path)
|
||||
{
|
||||
var serializer = GetType<IFileSerializer<TModel>>();
|
||||
if (serializer == null)
|
||||
return default;
|
||||
|
||||
return serializer.Serialize(obj, path);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IStreamSerializer.Serialize(T?)"/>
|
||||
public static Stream? SerializeStream(TModel? obj)
|
||||
{
|
||||
var serializer = GetType<IStreamSerializer<TModel>>();
|
||||
if (serializer == null)
|
||||
return default;
|
||||
|
||||
return serializer.Serialize(obj);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Get a constructed instance of a type, if possible
|
||||
/// </summary>
|
||||
/// <typeparam name="TSerializer">Serializer type to construct</typeparam>
|
||||
/// <returns>Serializer of the requested type, null on error</returns>
|
||||
private static TSerializer? GetType<TSerializer>()
|
||||
{
|
||||
// If the serializer type is invalid
|
||||
string? serializerName = typeof(TSerializer)?.Name;
|
||||
if (serializerName == null)
|
||||
return default;
|
||||
|
||||
// If the serializer has no generic arguments
|
||||
var genericArgs = typeof(TSerializer).GetGenericArguments();
|
||||
if (genericArgs == null || genericArgs.Length == 0)
|
||||
return default;
|
||||
|
||||
// Loop through all loaded assemblies
|
||||
Type modelType = genericArgs[0];
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
// If the assembly is invalid
|
||||
if (assembly == null)
|
||||
return default;
|
||||
|
||||
// If not all types can be loaded, use the ones that could be
|
||||
Type?[] assemblyTypes = [];
|
||||
try
|
||||
{
|
||||
assemblyTypes = assembly.GetTypes();
|
||||
}
|
||||
catch (ReflectionTypeLoadException rtle)
|
||||
{
|
||||
assemblyTypes = rtle.Types ?? [];
|
||||
}
|
||||
|
||||
// Loop through all types
|
||||
foreach (Type? type in assemblyTypes)
|
||||
{
|
||||
// If the type is invalid
|
||||
if (type == null)
|
||||
continue;
|
||||
|
||||
// If the type isn't a class
|
||||
if (!type.IsClass)
|
||||
continue;
|
||||
|
||||
// If the type doesn't implement the interface
|
||||
var interfaceType = type.GetInterface(serializerName);
|
||||
if (interfaceType == null)
|
||||
continue;
|
||||
|
||||
// If the interface doesn't use the correct type parameter
|
||||
var genericTypes = interfaceType.GetGenericArguments();
|
||||
if (genericTypes.Length != 1 || genericTypes[0] != modelType)
|
||||
continue;
|
||||
|
||||
// Try to create a concrete instance of the type
|
||||
var instance = (TSerializer?)Activator.CreateInstance(type);
|
||||
if (instance != null)
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user