Made JsonTypeSafeWrapper.Of generic to potentially avoid reflective instantiation

This commit is contained in:
Ell 2022-11-28 00:43:50 +01:00
parent d72b094a7a
commit 1a1b2025cd
4 changed files with 20 additions and 10 deletions

View File

@ -88,6 +88,7 @@ Improvements
- Added trimming and AOT annotations and made MLEM.Data trimmable
- Store a RuntimeTexturePacker packed texture region's source region
- Use JSON.NET attributes in favor of DataContract and DataMember
- Made JsonTypeSafeWrapper.Of generic to potentially avoid reflective instantiation
Fixes
- Fixed data texture atlases not allowing most characters in their region names

View File

@ -33,8 +33,7 @@ namespace MLEM.Data.Json {
} else {
if (this.data == null)
this.data = new Dictionary<string, JsonTypeSafeWrapper>();
// if types already match exactly, we don't need to use Of (which requires dynamic code)
this.data[key] = data.GetType() == typeof(T) ? new JsonTypeSafeWrapper<T>(data) : JsonTypeSafeWrapper.Of(data);
this.data[key] = JsonTypeSafeWrapper.Of(data);
}
}

View File

@ -29,17 +29,21 @@ namespace MLEM.Data.Json {
/// <summary>
/// Creates a new <see cref="JsonTypeSafeWrapper{T}"/> from the given value.
/// The type parameter of the returned wrapper will be equal to the <see cref="Type"/> of the <paramref name="value"/> passed.
/// If a <see cref="JsonTypeSafeWrapper{T}"/> for a specific type, known at comepile type, should be created, you can use <see cref="JsonTypeSafeWrapper{T}(T)"/>.
/// The type parameter of the returned wrapper will be equal to the <see cref="Type"/> of the <paramref name="value"/> passed, even if it is a subtype of <typeparamref name="T"/>.
/// If a <see cref="JsonTypeSafeWrapper{T}"/> for a specific type, known at compile type, should be created, you can use <see cref="JsonTypeSafeWrapper{T}(T)"/>.
/// </summary>
/// <param name="value">The value to wrap</param>
/// <returns>A <see cref="JsonTypeSafeWrapper{T}"/> with a type matching the type of <paramref name="value"/></returns>
#if NET7_0_OR_GREATER
[System.Diagnostics.CodeAnalysis.RequiresDynamicCode("The native code for this instantiation might not be available at runtime.")]
[System.Diagnostics.CodeAnalysis.RequiresDynamicCode("The native code for this instantiation might not be available at runtime if the value's type is a subtype of T.")]
#endif
public static JsonTypeSafeWrapper Of(object value) {
var type = typeof(JsonTypeSafeWrapper<>).MakeGenericType(value.GetType());
return (JsonTypeSafeWrapper) Activator.CreateInstance(type, value);
public static JsonTypeSafeWrapper Of<T>(T value) {
if (value.GetType() == typeof(T)) {
return new JsonTypeSafeWrapper<T>(value);
} else {
var type = typeof(JsonTypeSafeWrapper<>).MakeGenericType(value.GetType());
return (JsonTypeSafeWrapper) Activator.CreateInstance(type, value);
}
}
}
@ -55,7 +59,7 @@ namespace MLEM.Data.Json {
/// <summary>
/// Creates a new json type-safe wrapper instance that wraps the given <paramref name="value"/>.
/// If the type of the value is unknown at compile time, <see cref="JsonTypeSafeWrapper.Of"/> can be used instead.
/// If the type of the value is unknown at compile time, <see cref="JsonTypeSafeWrapper.Of{T}"/> can be used instead.
/// </summary>
/// <param name="value">The value to wrap</param>
public JsonTypeSafeWrapper(T value) {

View File

@ -40,9 +40,15 @@ public class DataTests {
var safeData = new JsonTypeSafeGenericDataHolder();
// data holder should wrap the time span to ensure that it stays a time span
safeData.SetData("Time", TimeSpan.FromMinutes(5));
// also check path that creates an instance through reflection
safeData.SetData<object>("Time2", TimeSpan.FromMinutes(15));
var safeRead = DataTests.SerializeAndDeserialize(safeData);
Assert.IsInstanceOf<TimeSpan>(safeRead.GetData<object>("Time"));
Assert.DoesNotThrow(() => safeRead.GetData<TimeSpan>("Time"));
Assert.AreEqual(TimeSpan.FromMinutes(5), safeRead.GetData<TimeSpan>("Time"));
Assert.IsInstanceOf<TimeSpan>(safeRead.GetData<object>("Time2"));
Assert.AreEqual(TimeSpan.FromMinutes(15), safeRead.GetData<TimeSpan>("Time2"));
}
private static T SerializeAndDeserialize<T>(T t) {