Skip to content

Commit 48ac495

Browse files
V2 Updates.
1 parent 79a2654 commit 48ac495

15 files changed

+241
-70
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
using Xunit;
3+
4+
namespace Open.Serialization.Tests
5+
{
6+
public static class DefaultImplementationTests
7+
{
8+
class A : IDeserializeObject
9+
{
10+
public object Deserialize(string value, Type type)
11+
{
12+
return 1;
13+
}
14+
}
15+
16+
class B : A
17+
{
18+
public T Deserialize<T>(string _)
19+
{
20+
return default;
21+
}
22+
}
23+
24+
[Fact]
25+
public static void DefaultImplementation()
26+
{
27+
IDeserializeObject a = new A();
28+
Assert.Equal(1, a.Deserialize<int>("0"));
29+
}
30+
}
31+
}
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>netcoreapp3.0</TargetFramework>
4+
<TargetFramework>netcoreapp3.1</TargetFramework>
55

66
<IsPackable>false</IsPackable>
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
10+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
1111
<PackageReference Include="xunit" Version="2.4.1" />
1212
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
1313
<PrivateAssets>all</PrivateAssets>
1414
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
1515
</PackageReference>
16-
<PackageReference Include="coverlet.collector" Version="1.1.0">
16+
<PackageReference Include="coverlet.collector" Version="1.2.0">
1717
<PrivateAssets>all</PrivateAssets>
1818
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
1919
</PackageReference>
@@ -23,6 +23,7 @@
2323
<ProjectReference Include="..\Open.Serialization.Json.Newtonsoft\Open.Serialization.Json.Newtonsoft.csproj" />
2424
<ProjectReference Include="..\Open.Serialization.Json.System\Open.Serialization.Json.System.csproj" />
2525
<ProjectReference Include="..\Open.Serialization.Json.Utf8Json\Open.Serialization.Json.Utf8Json.csproj" />
26+
<ProjectReference Include="..\Open.Serialization\Open.Serialization.csproj" />
2627
</ItemGroup>
2728

2829
</Project>
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Text;
5+
using System.Threading;
6+
using System.Threading.Tasks;
7+
8+
namespace Open.Serialization
9+
{
10+
/// <summary>
11+
/// Default utiltiy methods for use with implementing interfaces/classes.
12+
/// </summary>
13+
// Note: not implemented as extensions as it would cause ambiguity collisions
14+
// But retained public for use externally.
15+
public static class DefaultMethods
16+
{
17+
/// <inheritdoc cref="IDeserializeObjectAsync.DeserializeAsync(Stream, Type, CancellationToken))" />
18+
public static async ValueTask<object?> DeserializeAsync(IDeserializeObject deserializer, Stream source, Type type)
19+
{
20+
if (deserializer is null) throw new ArgumentNullException(nameof(deserializer));
21+
if (source is null) throw new ArgumentNullException(nameof(source));
22+
if (type is null) throw new ArgumentNullException(nameof(type));
23+
string text;
24+
using (var reader = new StreamReader(source))
25+
text = await reader.ReadToEndAsync().ConfigureAwait(false);
26+
return deserializer.Deserialize(text, type);
27+
}
28+
29+
/// <inheritdoc cref="ISerializeObjectAsync.SerializeAsync(Stream, object, Type, CancellationToken)"/>
30+
public static async ValueTask SerializeAsync(ISerializeObject serializer, Stream target, object? item, Type type)
31+
{
32+
if (serializer is null) throw new ArgumentNullException(nameof(serializer));
33+
if (target is null) throw new ArgumentNullException(nameof(target));
34+
if (type is null) throw new ArgumentNullException(nameof(type));
35+
var text = serializer.Serialize(item, type);
36+
using var writer = new StreamWriter(target);
37+
await writer.WriteAsync(text).ConfigureAwait(false);
38+
}
39+
40+
/// <inheritdoc cref="IDeserializeAsync.DeserializeAsync{T}(Stream, CancellationToken)"/>
41+
public static async ValueTask<T> DeserializeAsync<T>(IDeserialize deserializer, Stream source)
42+
{
43+
if (deserializer is null) throw new ArgumentNullException(nameof(deserializer));
44+
if (source is null) throw new ArgumentNullException(nameof(source));
45+
string text;
46+
using (var reader = new StreamReader(source))
47+
text = await reader.ReadToEndAsync().ConfigureAwait(false);
48+
return deserializer.Deserialize<T>(text);
49+
}
50+
51+
/// <inheritdoc cref="ISerializeAsync.SerializeAsync{T}(Stream, T, CancellationToken)"/>
52+
public static async ValueTask SerializeAsync<T>(ISerialize serializer, Stream target, T item)
53+
{
54+
if (serializer is null) throw new ArgumentNullException(nameof(serializer));
55+
if (target is null) throw new ArgumentNullException(nameof(target));
56+
57+
var text = serializer.Serialize(item);
58+
using var writer = new StreamWriter(target);
59+
await writer.WriteAsync(text).ConfigureAwait(false);
60+
}
61+
62+
63+
/// <inheritdoc cref="IDeserializeAsync{T}.DeserializeAsync(Stream, CancellationToken)"/>
64+
public static async ValueTask<T> DeserializeAsync<T>(IDeserialize<T> deserializer, Stream source)
65+
{
66+
if (deserializer is null) throw new ArgumentNullException(nameof(deserializer));
67+
if (source is null) throw new ArgumentNullException(nameof(source));
68+
string text;
69+
using (var reader = new StreamReader(source))
70+
text = await reader.ReadToEndAsync().ConfigureAwait(false);
71+
return deserializer.Deserialize(text);
72+
}
73+
74+
/// <inheritdoc cref="ISerializeAsync{T}.SerializeAsync(Stream, T, CancellationToken)"/>
75+
public static async ValueTask SerializeAsync<T>(ISerialize<T> serializer, Stream target, T item)
76+
{
77+
if (serializer is null) throw new ArgumentNullException(nameof(serializer));
78+
if (target is null) throw new ArgumentNullException(nameof(target));
79+
80+
var text = serializer.Serialize(item);
81+
using var writer = new StreamWriter(target);
82+
await writer.WriteAsync(text).ConfigureAwait(false);
83+
}
84+
85+
}
86+
}

Open.Serialization/IDeserialize.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
namespace Open.Serialization
1+
using System.IO;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
5+
namespace Open.Serialization
26
{
37
/// <summary>
48
/// Interface for deserializing any given generic type.
@@ -11,6 +15,11 @@ public interface IDeserialize
1115
/// <param name="value">The string to deserialize.</param>
1216
/// <returns>The deserialized result.</returns>
1317
T Deserialize<T>(string? value);
18+
19+
#if NETSTANDARD2_1
20+
ValueTask<T> DeserializeAsync<T>(Stream source, CancellationToken cancellationToken = default)
21+
=> DefaultMethods.DeserializeAsync<T>(this, source);
22+
#endif
1423
}
1524

1625
/// <summary>
Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
using System;
2+
using System.IO;
3+
using System.Threading;
4+
using System.Threading.Tasks;
25

36
namespace Open.Serialization
47
{
58
/// <summary>
69
/// Interface for deserializing any string to an object when given a type.
710
/// </summary>
8-
public interface IDeserializeObject : IDeserialize
11+
public interface IDeserializeObject
912
{
1013
/// <summary>
1114
/// Deserializes a string value to the specified type.
@@ -16,9 +19,17 @@ public interface IDeserializeObject : IDeserialize
1619
object? Deserialize(string? value, Type type);
1720

1821
#if NETSTANDARD2_1
19-
T IDeserialize.Deserialize<T>(string? value)
22+
/// <inheritdoc cref="IDeserialize.Deserialize{T}(string)" />
23+
T Deserialize<T>(string? value)
2024
=> (T)Deserialize(value, typeof(T))!;
21-
#endif
2225

26+
/// <inheritdoc cref="IDeserializeObjectAsync.DeserializeAsync(Stream, Type, CancellationToken)" />
27+
ValueTask<object?> DeserializeAsync(Stream source, Type type, CancellationToken cancellationToken = default)
28+
=> DefaultMethods.DeserializeAsync(this, source, type);
29+
30+
/// <inheritdoc cref="IDeserializeAsync.DeserializeAsync{T}(Stream, CancellationToken)" />
31+
async ValueTask<T> DeserializeAsync<T>(Stream source, CancellationToken cancellationToken)
32+
=> (T)(await DeserializeAsync(source, typeof(T), cancellationToken))!;
33+
#endif
2334
}
2435
}

Open.Serialization/IDeserializeObjectAsync.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace Open.Serialization
88
/// <summary>
99
/// Interface for asynchronously deserializing any string to an object when given a type.
1010
/// </summary>
11-
public interface IDeserializeObjectAsync : IDeserializeAsync
11+
public interface IDeserializeObjectAsync
1212
{
1313
/// <summary>
1414
/// Deserializes a stream to the specified type.
@@ -20,7 +20,8 @@ public interface IDeserializeObjectAsync : IDeserializeAsync
2020
ValueTask<object?> DeserializeAsync(Stream source, Type type, CancellationToken cancellationToken = default);
2121

2222
#if NETSTANDARD2_1
23-
async ValueTask<T> IDeserializeAsync.DeserializeAsync<T>(Stream source, CancellationToken cancellationToken)
23+
/// <inheritdoc cref="IDeserializeAsync.DeserializeAsync{T}(Stream, CancellationToken)" />
24+
async ValueTask<T> DeserializeAsync<T>(Stream source, CancellationToken cancellationToken)
2425
=> (T)(await DeserializeAsync(source, typeof(T), cancellationToken))!;
2526
#endif
2627
}

Open.Serialization/ISerialize.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
namespace Open.Serialization
1+
using System.IO;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
5+
namespace Open.Serialization
26
{
37
/// <summary>
48
/// Interface for serializing a given generic type.
@@ -11,6 +15,11 @@ public interface ISerialize
1115
/// <param name="item">The item to deserialze.</param>
1216
/// <returns>The serialized string.</returns>
1317
string? Serialize<T>(T item);
18+
19+
#if NETSTANDARD2_1
20+
ValueTask SerializeAsync<T>(Stream target, T item, CancellationToken cancellationToken = default)
21+
=> DefaultMethods.SerializeAsync<T>(this, target, item);
22+
#endif
1423
}
1524

1625

Open.Serialization/ISerializeObject.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
using System;
2+
using System.IO;
3+
using System.Threading;
4+
using System.Threading.Tasks;
25

36
namespace Open.Serialization
47
{
58
/// <summary>
69
/// Interface for serializing an object to a string when given a type.
710
/// </summary>
8-
public interface ISerializeObject : ISerialize
11+
public interface ISerializeObject
912
{
1013
/// <summary>
1114
/// Serializes the provided item to a string.
@@ -16,8 +19,17 @@ public interface ISerializeObject : ISerialize
1619
string? Serialize(object? item, Type type);
1720

1821
#if NETSTANDARD2_1
19-
string? ISerialize.Serialize<T>(T item)
22+
/// <inheritdoc cref="ISerialize" />
23+
string? Serialize<T>(T item)
2024
=> Serialize(item, typeof(T));
25+
26+
/// <inheritdoc cref="ISerializeObjectAsync.SerializeAsync(Stream, object, Type, CancellationToken)"/>
27+
ValueTask SerializeAsync(Stream target, object? item, Type type, CancellationToken cancellationToken = default)
28+
=> DefaultMethods.SerializeAsync(this, target, item, type);
29+
30+
/// <inheritdoc cref="ISerializeAsync.SerializeAsync{T}(Stream, T, CancellationToken)" />
31+
virtual ValueTask SerializeAsync<T>(Stream target, T item, CancellationToken cancellationToken)
32+
=> SerializeAsync(target, item, typeof(T), cancellationToken);
2133
#endif
2234
}
2335
}

Open.Serialization/ISerializeObjectAsync.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace Open.Serialization
88
/// <summary>
99
/// Interface for asynchronously serializing an object to a string when given a type.
1010
/// </summary>
11-
public interface ISerializeObjectAsync : ISerializeAsync
11+
public interface ISerializeObjectAsync
1212
{
1313
/// <summary>
1414
/// Serializes the provided item to a stream.
@@ -20,7 +20,8 @@ public interface ISerializeObjectAsync : ISerializeAsync
2020
ValueTask SerializeAsync(Stream target, object? item, Type type, CancellationToken cancellationToken = default);
2121

2222
#if NETSTANDARD2_1
23-
ValueTask ISerializeAsync.SerializeAsync<T>(Stream target, T item, CancellationToken cancellationToken)
23+
/// <inheritdoc cref="ISerializeAsync.SerializeAsync{T}(Stream, T, CancellationToken)" />
24+
virtual ValueTask SerializeAsync<T>(Stream target, T item, CancellationToken cancellationToken)
2425
=> SerializeAsync(target, item, typeof(T), cancellationToken);
2526
#endif
2627
}

Open.Serialization/ObjectSerializer.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Diagnostics.Contracts;
23
using System.IO;
34
using System.Threading;
45
using System.Threading.Tasks;
@@ -10,7 +11,7 @@ namespace Open.Serialization
1011
/// </summary>
1112
public abstract class ObjectSerializer : ObjectSerializerBase
1213
{
13-
private readonly Func<string?, Type, object?> _deserializer;
14+
private readonly Func<string?, Type, object?>? _deserializer;
1415
private readonly Func<object?, Type, string?>? _serializer;
1516
private readonly Func<Stream, Type, CancellationToken, ValueTask<object?>> _deserializerAsync;
1617
private readonly Func<Stream, object?, Type, CancellationToken, ValueTask> _serializerAsync;
@@ -19,20 +20,26 @@ public abstract class ObjectSerializer : ObjectSerializerBase
1920
/// Constructs a serializer/deserializer using the provided serialization functions.
2021
/// </summary>
2122
public ObjectSerializer(
22-
Func<string?, Type, object?> deserializer,
23+
Func<string?, Type, object?>? deserializer,
2324
Func<object?, Type, string?>? serializer = null,
2425
Func<Stream, Type, CancellationToken, ValueTask<object?>>? deserializerAsync = null,
2526
Func<Stream, object?, Type, CancellationToken, ValueTask>? serializerAsync = null)
2627
{
27-
_deserializer = deserializer ?? throw new ArgumentNullException(nameof(deserializer));
28+
if (deserializer is null && serializer is null && deserializerAsync is null && serializerAsync is null)
29+
throw new ArgumentNullException(nameof(deserializer), "At least one of the serialization or deserialization functions must not be null.");
30+
Contract.EndContractBlock();
31+
32+
_deserializer = deserializer;
2833
_serializer = serializer;
2934
_deserializerAsync = deserializerAsync ?? base.DeserializeAsync;
3035
_serializerAsync = serializerAsync ?? base.SerializeAsync;
3136
}
3237

3338
/// <inheritdoc />
3439
public override object? Deserialize(string? value, Type type)
35-
=> _deserializer(value, type);
40+
=> _deserializer == null
41+
? throw new NullReferenceException("No deserializer function was supplied.")
42+
: _deserializer(value, type);
3643

3744
/// <inheritdoc />
3845
public override ValueTask<object?> DeserializeAsync(Stream stream, Type type, CancellationToken cancellationToken = default)

0 commit comments

Comments
 (0)