From 053a0581fdfada20df6a0f131d6e713fadf95830 Mon Sep 17 00:00:00 2001 From: MartinYl <83362632@qq.com> Date: Tue, 17 Nov 2020 21:44:48 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E6=89=A9=E5=B1=95EasyCaching.Serialization?= =?UTF-8?q?.System.Text.Json=EF=BC=8C=E4=BD=BF=E7=94=A8System.Text.Json?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E5=BA=8F=E5=88=97=E5=8C=96=E5=92=8C=E5=8F=8D?= =?UTF-8?q?=E5=BA=8F=E5=88=97=E5=8C=96json?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- EasyCaching.sln | 7 ++ .../EasyCachingJsonSerializerOptions.cs | 94 +++++++++++++++++++ .../EasyCachingOptionsExtensions.cs | 71 ++++++++++++++ .../Configurations/JsonOptionsExtension.cs | 51 ++++++++++ .../DefaultJsonSerializer.cs | 88 +++++++++++++++++ ...aching.Serialization.SystemTextJson.csproj | 15 +++ .../EasyCaching.UnitTests.csproj | 1 + .../SystemTestJsonSerializerTest.cs | 72 ++++++++++++++ 8 files changed, 399 insertions(+) create mode 100644 serialization/EasyCaching.Serialization.SystemTextJson/Configurations/EasyCachingJsonSerializerOptions.cs create mode 100644 serialization/EasyCaching.Serialization.SystemTextJson/Configurations/EasyCachingOptionsExtensions.cs create mode 100644 serialization/EasyCaching.Serialization.SystemTextJson/Configurations/JsonOptionsExtension.cs create mode 100644 serialization/EasyCaching.Serialization.SystemTextJson/DefaultJsonSerializer.cs create mode 100644 serialization/EasyCaching.Serialization.SystemTextJson/EasyCaching.Serialization.SystemTextJson.csproj create mode 100644 test/EasyCaching.UnitTests/SerializerTests/SystemTestJsonSerializerTest.cs diff --git a/EasyCaching.sln b/EasyCaching.sln index bfd9e15d..a595298f 100644 --- a/EasyCaching.sln +++ b/EasyCaching.sln @@ -68,6 +68,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "bus", "bus", "{B337509B-75F EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyCaching.LiteDB", "src\EasyCaching.LiteDB\EasyCaching.LiteDB.csproj", "{BA850294-3103-4540-8A27-FC768E1DC8FC}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyCaching.Serialization.SystemTextJson", "serialization\EasyCaching.Serialization.SystemTextJson\EasyCaching.Serialization.SystemTextJson.csproj", "{4FCF16BF-5E21-4B74-AB45-3C121ADF1485}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -178,6 +180,10 @@ Global {BA850294-3103-4540-8A27-FC768E1DC8FC}.Debug|Any CPU.Build.0 = Debug|Any CPU {BA850294-3103-4540-8A27-FC768E1DC8FC}.Release|Any CPU.ActiveCfg = Release|Any CPU {BA850294-3103-4540-8A27-FC768E1DC8FC}.Release|Any CPU.Build.0 = Release|Any CPU + {4FCF16BF-5E21-4B74-AB45-3C121ADF1485}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4FCF16BF-5E21-4B74-AB45-3C121ADF1485}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4FCF16BF-5E21-4B74-AB45-3C121ADF1485}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4FCF16BF-5E21-4B74-AB45-3C121ADF1485}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -209,6 +215,7 @@ Global {43AD80E9-696B-4042-9D50-B26F48BE1928} = {A0F5CC7E-155F-4726-8DEB-E966950B3FE9} {711603E1-8363-4F8D-9AA9-8C03EC8BD35F} = {B4241D34-A973-4A13-BD89-9BAE3F2BDDF6} {BA850294-3103-4540-8A27-FC768E1DC8FC} = {A0F5CC7E-155F-4726-8DEB-E966950B3FE9} + {4FCF16BF-5E21-4B74-AB45-3C121ADF1485} = {15070C49-A507-4844-BCFE-D319CFBC9A63} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {63A57886-054B-476C-AAE1-8D7C8917682E} diff --git a/serialization/EasyCaching.Serialization.SystemTextJson/Configurations/EasyCachingJsonSerializerOptions.cs b/serialization/EasyCaching.Serialization.SystemTextJson/Configurations/EasyCachingJsonSerializerOptions.cs new file mode 100644 index 00000000..63e80eb3 --- /dev/null +++ b/serialization/EasyCaching.Serialization.SystemTextJson/Configurations/EasyCachingJsonSerializerOptions.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Text.Encodings.Web; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace EasyCaching.Serialization.SystemTextJson.Configurations +{ + public class EasyCachingJsonSerializerOptions + { + /// + /// Gets or sets the encoder to use when escaping strings, or null to use the default + /// encoder. + /// + public JavaScriptEncoder Encoder => JavaScriptEncoder.UnsafeRelaxedJsonEscaping; + /// + /// Gets or sets a value that defines how comments are handled during deserialization. + /// + public JsonCommentHandling ReadCommentHandling => JsonCommentHandling.Disallow; + /// + /// Gets or sets a value that specifies the policy used to convert a property's name + /// on an object to another format, such as camel-casing, or null to leave property + /// names unchanged. + /// + public JsonNamingPolicy PropertyNamingPolicy => null; + /// + /// Gets or sets a value that determines whether a property's name uses a case-insensitive + /// comparison during deserialization. The default value is false. + /// + public bool PropertyNameCaseInsensitive => false; + /// + /// Specifies how number types should be handled when serializing or deserializing. + /// + public JsonNumberHandling NumberHandling => JsonNumberHandling.Strict; + /// + /// Gets or sets the maximum depth allowed when serializing or deserializing JSON, + /// with the default value of 0 indicating a maximum depth of 64. + /// + public int MaxDepth => 0; + /// + /// Determines whether fields are handled serialization and deserialization. The + /// default value is false. + /// + public bool IncludeFields => false; + /// + /// Gets a value that determines whether read-only properties are ignored during + /// serialization. The default value is false. + /// + public bool IgnoreReadOnlyProperties => false; + /// + /// Determines whether read-only fields are ignored during serialization. A property + /// is read-only if it isn't marked with the readonly keyword. The default value is false. + /// + public bool IgnoreReadOnlyFields => false; + /// + /// Gets or sets a value that determines whether null values are ignored during serialization + /// and deserialization. The default value is false. + /// + public bool IgnoreNullValues = false; + /// + /// Gets or sets the policy used to convert a System.Collections.IDictionary key's + /// name to another format, such as camel-casing. + /// + public JsonNamingPolicy DictionaryKeyPolicy => null; + /// + /// Specifies a condition to determine when properties with default values are ignored + /// during serialization or deserialization. The default value is System.Text.Json.Serialization.JsonIgnoreCondition.Never. + /// + public JsonIgnoreCondition DefaultIgnoreCondition => JsonIgnoreCondition.Never; + /// + /// Gets or sets the default buffer size, in bytes, to use when creating temporary buffers. + /// + public int DefaultBufferSize => 16 * 1024; + /// + /// Gets the list of user-defined converters that were registered. + /// + public IList Converters => new List(); + /// + /// Get or sets a value that indicates whether an extra comma at the end of a list + /// of JSON values in an object or array is allowed (and ignored) within the JSON + /// payload being deserialized. + /// + public bool AllowTrailingCommas => false; + /// + /// Configures how object references are handled when reading and writing JSON. + /// + public ReferenceHandler ReferenceHandler => null; + /// + /// Gets or sets a value that defines whether JSON should use pretty printing. By + /// default, JSON is serialized without any extra white space. + /// + public bool WriteIndented => false; + } +} diff --git a/serialization/EasyCaching.Serialization.SystemTextJson/Configurations/EasyCachingOptionsExtensions.cs b/serialization/EasyCaching.Serialization.SystemTextJson/Configurations/EasyCachingOptionsExtensions.cs new file mode 100644 index 00000000..88b2f1d1 --- /dev/null +++ b/serialization/EasyCaching.Serialization.SystemTextJson/Configurations/EasyCachingOptionsExtensions.cs @@ -0,0 +1,71 @@ +using EasyCaching.Core.Configurations; +using System; +using System.Linq; +using System.Text.Json; + +namespace EasyCaching.Serialization.SystemTextJson.Configurations +{ + + /// + /// EasyCaching options extensions. + /// + public static class EasyCachingOptionsExtensions + { + /// + /// Withs the json serializer. + /// + /// Options. + /// The name of this serializer instance. + public static EasyCachingOptions WithJson(this EasyCachingOptions options, string name = "json") => options.WithJson(configure: x => { }, name); + + /// + /// Withs the json serializer. + /// + /// Options. + /// Configure serializer settings. + /// The name of this serializer instance. + public static EasyCachingOptions WithJson(this EasyCachingOptions options, Action configure, string name) + { + var easyCachingJsonSerializerOptions = new EasyCachingJsonSerializerOptions(); + + configure(easyCachingJsonSerializerOptions); + + void jsonSerializerSettings(JsonSerializerOptions x) + { + x.MaxDepth = easyCachingJsonSerializerOptions.MaxDepth; + x.AllowTrailingCommas = easyCachingJsonSerializerOptions.AllowTrailingCommas; + x.Converters.Union(easyCachingJsonSerializerOptions.Converters); + x.DefaultBufferSize = easyCachingJsonSerializerOptions.DefaultBufferSize; + x.DefaultIgnoreCondition = easyCachingJsonSerializerOptions.DefaultIgnoreCondition; + x.DictionaryKeyPolicy = easyCachingJsonSerializerOptions.DictionaryKeyPolicy; + x.Encoder = easyCachingJsonSerializerOptions.Encoder; + x.IgnoreReadOnlyFields = easyCachingJsonSerializerOptions.IgnoreReadOnlyFields; + x.IgnoreReadOnlyProperties = easyCachingJsonSerializerOptions.IgnoreReadOnlyProperties; + x.IncludeFields = easyCachingJsonSerializerOptions.IncludeFields; + x.NumberHandling = easyCachingJsonSerializerOptions.NumberHandling; + x.PropertyNameCaseInsensitive = easyCachingJsonSerializerOptions.PropertyNameCaseInsensitive; + x.PropertyNamingPolicy = easyCachingJsonSerializerOptions.PropertyNamingPolicy; + x.ReadCommentHandling = easyCachingJsonSerializerOptions.ReadCommentHandling; + x.ReferenceHandler = easyCachingJsonSerializerOptions.ReferenceHandler; + x.WriteIndented = easyCachingJsonSerializerOptions.WriteIndented; + } + + options.RegisterExtension(new JsonOptionsExtension(name, jsonSerializerSettings)); + + return options; + } + + /// + /// Withs the json serializer. + /// + /// Options. + /// Configure serializer settings. + /// The name of this serializer instance. + public static EasyCachingOptions WithJson(this EasyCachingOptions options, Action jsonSerializerSettingsConfigure, string name) + { + options.RegisterExtension(new JsonOptionsExtension(name, jsonSerializerSettingsConfigure)); + + return options; + } + } +} \ No newline at end of file diff --git a/serialization/EasyCaching.Serialization.SystemTextJson/Configurations/JsonOptionsExtension.cs b/serialization/EasyCaching.Serialization.SystemTextJson/Configurations/JsonOptionsExtension.cs new file mode 100644 index 00000000..cf61886f --- /dev/null +++ b/serialization/EasyCaching.Serialization.SystemTextJson/Configurations/JsonOptionsExtension.cs @@ -0,0 +1,51 @@ +using EasyCaching.Core.Configurations; +using EasyCaching.Core.Serialization; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Text.Json; + +namespace EasyCaching.Serialization.SystemTextJson +{ + /// + /// Json options extension. + /// + internal sealed class JsonOptionsExtension : IEasyCachingOptionsExtension + { + /// + /// The name. + /// + private readonly string _name; + + /// + /// The configure. + /// + private readonly Action _configure; + + /// + /// Initializes a new instance of the class. + /// + /// Name. + /// Configure. + public JsonOptionsExtension(string name, Action configure) + { + _name = name; + _configure = configure; + } + + public void AddServices(IServiceCollection services) + { + Action configure = x => { }; + + if (_configure != null) configure = _configure; + + services.AddOptions(); + services.Configure(_name, configure); + services.AddSingleton(x => + { + var optionsMon = x.GetRequiredService>(); + var options = optionsMon.Get(_name); + return new DefaultJsonSerializer(_name, options); + }); + } + } +} diff --git a/serialization/EasyCaching.Serialization.SystemTextJson/DefaultJsonSerializer.cs b/serialization/EasyCaching.Serialization.SystemTextJson/DefaultJsonSerializer.cs new file mode 100644 index 00000000..ef73eb1c --- /dev/null +++ b/serialization/EasyCaching.Serialization.SystemTextJson/DefaultJsonSerializer.cs @@ -0,0 +1,88 @@ +using EasyCaching.Core.Serialization; +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.Json; + +namespace EasyCaching.Serialization.SystemTextJson +{ + /// + /// Default json serializer. + /// + public class DefaultJsonSerializer : IEasyCachingSerializer + { + /// + /// The json serializer. + /// + private readonly JsonSerializerOptions jsonSerializerOption; + /// + /// The name. + /// + private readonly string _name; + /// + /// Gets the name. + /// + /// The name. + public string Name => _name; + + /// + /// Initializes a new instance of the class. + /// + /// Name. + /// serializerSettings. + public DefaultJsonSerializer(string name, JsonSerializerOptions serializerSettings) + { + _name = name; + jsonSerializerOption = serializerSettings; + } + + /// + /// Deserialize the specified bytes. + /// + /// The deserialize. + /// Bytes. + /// The 1st type parameter. + public T Deserialize(byte[] bytes) + { + return JsonSerializer.Deserialize(bytes, jsonSerializerOption); + } + /// + /// Deserialize the specified bytes. + /// + /// The deserialize. + /// Bytes. + /// Type. + public object Deserialize(byte[] bytes, Type type) + { + return JsonSerializer.Deserialize(bytes, type, jsonSerializerOption); + } + /// + /// Deserializes the object. + /// + /// The object. + /// Value. + public object DeserializeObject(ArraySegment value) + { + return JsonSerializer.Deserialize(value, jsonSerializerOption); + } + /// + /// Serialize the specified value. + /// + /// The serialize. + /// Value. + /// The 1st type parameter. + public byte[] Serialize(T value) + { + return JsonSerializer.SerializeToUtf8Bytes(value, jsonSerializerOption); + } + /// + /// Serializes the object. + /// + /// The object. + /// Object. + public ArraySegment SerializeObject(object obj) + { + return new ArraySegment(JsonSerializer.SerializeToUtf8Bytes(obj, jsonSerializerOption)); + } + } +} diff --git a/serialization/EasyCaching.Serialization.SystemTextJson/EasyCaching.Serialization.SystemTextJson.csproj b/serialization/EasyCaching.Serialization.SystemTextJson/EasyCaching.Serialization.SystemTextJson.csproj new file mode 100644 index 00000000..4f582f9a --- /dev/null +++ b/serialization/EasyCaching.Serialization.SystemTextJson/EasyCaching.Serialization.SystemTextJson.csproj @@ -0,0 +1,15 @@ + + + + netstandard2.0 + + + + + + + + + + + diff --git a/test/EasyCaching.UnitTests/EasyCaching.UnitTests.csproj b/test/EasyCaching.UnitTests/EasyCaching.UnitTests.csproj index c02fee37..24533c83 100644 --- a/test/EasyCaching.UnitTests/EasyCaching.UnitTests.csproj +++ b/test/EasyCaching.UnitTests/EasyCaching.UnitTests.csproj @@ -38,6 +38,7 @@ + diff --git a/test/EasyCaching.UnitTests/SerializerTests/SystemTestJsonSerializerTest.cs b/test/EasyCaching.UnitTests/SerializerTests/SystemTestJsonSerializerTest.cs new file mode 100644 index 00000000..38db6210 --- /dev/null +++ b/test/EasyCaching.UnitTests/SerializerTests/SystemTestJsonSerializerTest.cs @@ -0,0 +1,72 @@ +using EasyCaching.Serialization.SystemTextJson; +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Xunit; + +namespace EasyCaching.UnitTests.SerializerTests +{ + public class SystemTestJsonSerializerTest : BaseSerializerTest + { + public SystemTestJsonSerializerTest() + { + _serializer = new DefaultJsonSerializer("json", new System.Text.Json.JsonSerializerOptions()); + } + + [Fact] + public void Isuue_50_Test() + { + Employee joe = new Employee { Name = "Joe User" }; + Employee mike = new Employee { Name = "Mike Manager" }; + joe.Manager = mike; + mike.Manager = mike; + + Assert.Throws(() => _serializer.Serialize(joe)); + } + + [Fact] + public void ReferenceLoopHandling_Test_Should_Succeed() + { + var serializer = new DefaultJsonSerializer("json", new JsonSerializerOptions() + { + ReferenceHandler = ReferenceHandler.Preserve + }); + + Employee joe = new Employee { Name = "Joe User" }; + Employee mike = new Employee { Name = "Mike Manager" }; + joe.Manager = mike; + mike.Manager = mike; + + var joe_byte = serializer.Serialize(joe); + var joe_obj = serializer.Deserialize(joe_byte); + + + Assert.Equal(joe.Name, joe_obj.Name); + Assert.Equal(joe.Manager, mike); + } + + public class Employee + { + public string Name { get; set; } + public Employee Manager { get; set; } + } + + [Fact] + public void NullValueHandling_Test_Should_Succeed() + { + var serializer = new DefaultJsonSerializer("json", new JsonSerializerOptions + { + IgnoreNullValues = true + }); + + Employee joe = new Employee { Name = "Joe User" }; + + var joe_byte = serializer.Serialize(joe); + var joe_obj = serializer.Deserialize(joe_byte); + + Assert.Null(joe.Manager); + } + } +} \ No newline at end of file From 07a747c37a2b7e69e87913ef1da07f2109185cc5 Mon Sep 17 00:00:00 2001 From: ccb Date: Wed, 18 Nov 2020 10:53:11 +0800 Subject: [PATCH 2/3] fixed UnitTest Error --- .../EasyCachingOptionsExtensions.cs | 6 +-- .../DefaultJsonSerializer.cs | 40 ++++++++++++++++--- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/serialization/EasyCaching.Serialization.SystemTextJson/Configurations/EasyCachingOptionsExtensions.cs b/serialization/EasyCaching.Serialization.SystemTextJson/Configurations/EasyCachingOptionsExtensions.cs index 88b2f1d1..885572a2 100644 --- a/serialization/EasyCaching.Serialization.SystemTextJson/Configurations/EasyCachingOptionsExtensions.cs +++ b/serialization/EasyCaching.Serialization.SystemTextJson/Configurations/EasyCachingOptionsExtensions.cs @@ -16,7 +16,7 @@ public static class EasyCachingOptionsExtensions /// /// Options. /// The name of this serializer instance. - public static EasyCachingOptions WithJson(this EasyCachingOptions options, string name = "json") => options.WithJson(configure: x => { }, name); + public static EasyCachingOptions WithSystemTextJson(this EasyCachingOptions options, string name = "json") => options.WithSystemTextJson(configure: x => { }, name); /// /// Withs the json serializer. @@ -24,7 +24,7 @@ public static class EasyCachingOptionsExtensions /// Options. /// Configure serializer settings. /// The name of this serializer instance. - public static EasyCachingOptions WithJson(this EasyCachingOptions options, Action configure, string name) + public static EasyCachingOptions WithSystemTextJson(this EasyCachingOptions options, Action configure, string name) { var easyCachingJsonSerializerOptions = new EasyCachingJsonSerializerOptions(); @@ -61,7 +61,7 @@ void jsonSerializerSettings(JsonSerializerOptions x) /// Options. /// Configure serializer settings. /// The name of this serializer instance. - public static EasyCachingOptions WithJson(this EasyCachingOptions options, Action jsonSerializerSettingsConfigure, string name) + public static EasyCachingOptions WithSystemTextJson(this EasyCachingOptions options, Action jsonSerializerSettingsConfigure, string name) { options.RegisterExtension(new JsonOptionsExtension(name, jsonSerializerSettingsConfigure)); diff --git a/serialization/EasyCaching.Serialization.SystemTextJson/DefaultJsonSerializer.cs b/serialization/EasyCaching.Serialization.SystemTextJson/DefaultJsonSerializer.cs index ef73eb1c..dc2a6b44 100644 --- a/serialization/EasyCaching.Serialization.SystemTextJson/DefaultJsonSerializer.cs +++ b/serialization/EasyCaching.Serialization.SystemTextJson/DefaultJsonSerializer.cs @@ -1,6 +1,7 @@ -using EasyCaching.Core.Serialization; +using EasyCaching.Core.Internal; +using EasyCaching.Core.Serialization; using System; -using System.Collections.Generic; +using System.IO; using System.Text; using System.Text.Json; @@ -63,10 +64,24 @@ public object Deserialize(byte[] bytes, Type type) /// Value. public object DeserializeObject(ArraySegment value) { - return JsonSerializer.Deserialize(value, jsonSerializerOption); + var jr = new Utf8JsonReader(value); + jr.Read(); + if (jr.TokenType == JsonTokenType.StartArray) + { + jr.Read(); + var typeName = Encoding.UTF8.GetString(jr.ValueSpan.ToArray()); + var type = Type.GetType(typeName, throwOnError: true); + + jr.Read(); + return JsonSerializer.Deserialize(ref jr, type, jsonSerializerOption); + } + else + { + throw new InvalidDataException("JsonTranscoder only supports [\"TypeName\", object]"); + } } /// - /// Serialize the specified value. + //; Serialize the specified value. /// /// The serialize. /// Value. @@ -82,7 +97,22 @@ public byte[] Serialize(T value) /// Object. public ArraySegment SerializeObject(object obj) { - return new ArraySegment(JsonSerializer.SerializeToUtf8Bytes(obj, jsonSerializerOption)); + var typeName = TypeHelper.BuildTypeName(obj.GetType()); + + using (var ms = new MemoryStream()) + using (var jw = new Utf8JsonWriter(ms)) + { + jw.WriteStartArray(); + jw.WriteStringValue(typeName); + + JsonSerializer.Serialize(jw, obj, jsonSerializerOption); + + jw.WriteEndArray(); + + jw.Flush(); + + return new ArraySegment(ms.ToArray(), 0, (int)ms.Length); + } } } } From 596874b9072b883fd8dbbe62fe2f0edd5b11a795 Mon Sep 17 00:00:00 2001 From: ccb Date: Wed, 18 Nov 2020 13:27:09 +0800 Subject: [PATCH 3/3] TrySet_Parallel_Should_Succeed --- .../CachingTests/MemoryCachingProviderTest.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/EasyCaching.UnitTests/CachingTests/MemoryCachingProviderTest.cs b/test/EasyCaching.UnitTests/CachingTests/MemoryCachingProviderTest.cs index 3e07841d..5738e81d 100644 --- a/test/EasyCaching.UnitTests/CachingTests/MemoryCachingProviderTest.cs +++ b/test/EasyCaching.UnitTests/CachingTests/MemoryCachingProviderTest.cs @@ -53,7 +53,6 @@ public void TrySet_Parallel_Should_Succeed() }); Assert.Equal(1, list.Count(x => x)); - } [Fact]