diff --git a/Core/Data/Result/ConciseModel.cs b/Core/Data/Result/ConciseModel.cs index a0fe553..2ed8503 100644 --- a/Core/Data/Result/ConciseModel.cs +++ b/Core/Data/Result/ConciseModel.cs @@ -59,7 +59,7 @@ public ConciseModel(string id, string title, string link = null, string descript /// Gets or sets the identifier. /// [JsonPropertyName("id")] - [Description("The identifier of the model.")] + [Description("The identifier of the item.")] public string Id { get => GetCurrentProperty(); @@ -70,7 +70,7 @@ public string Id /// Gets or sets the title. /// [JsonPropertyName("title")] - [Description("The title of the model.")] + [Description("The title of the item.")] public string Title { get => GetCurrentProperty(); @@ -82,7 +82,7 @@ public string Title /// [JsonPropertyName("desc")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [Description("The short description of the model.")] + [Description("The short description of the item.")] public string Description { get => GetCurrentProperty(); @@ -102,9 +102,9 @@ public Uri ImageUri /// /// Gets or sets the image URI (thumbnail or avatar). /// - [JsonPropertyName("id")] + [JsonPropertyName("image")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [Description("The thumbnail or avatar URL of the model.")] + [Description("The thumbnail or avatar URL of the item.")] public string ImageUrl { get => ImageUri?.OriginalString; @@ -116,7 +116,7 @@ public string ImageUrl /// [JsonPropertyName("url")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [Description("The URL to details page of the model.")] + [Description("The URL to details page of the item.")] public string Link { get => GetCurrentProperty(); @@ -128,7 +128,8 @@ public string Link /// [JsonPropertyName("keywords")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [Description("The keywords of the model.")] + [Description("The keywords of the item.")] + [JsonConverter(typeof(JsonStringListConverter.SemicolonSeparatedConverter))] public ObservableCollection Keywords { get => GetCurrentProperty>(); @@ -216,7 +217,7 @@ public override string ToString() } /// -/// The model with observable name and value. +/// The model with observable key and value. /// /// The type of the value. [DataContract] @@ -232,16 +233,16 @@ public KeyValueObservableModel() /// /// Initializes a new instance of the KeyValueObservableModel class. /// - /// The name. + /// The key. /// The value. - public KeyValueObservableModel(string name, T value) + public KeyValueObservableModel(string key, T value) { - Key = name; + Key = key; Value = value; } /// - /// Gets or sets the name. + /// Gets or sets the key. /// [DataMember(Name = "key")] [JsonPropertyName("key")] @@ -275,3 +276,64 @@ public object Tag set => SetCurrentProperty(value); } } + +/// +/// The model with observable name and value. +/// +/// The type of the value. +[DataContract] +public class NameValueObservableModel : BaseObservableProperties +{ + /// + /// Initializes a new instance of the NameValueObservableModel class. + /// + public NameValueObservableModel() + { + } + + /// + /// Initializes a new instance of the NameValueObservableModel class. + /// + /// The name. + /// The value. + public NameValueObservableModel(string name, T value) + { + Name = name; + Value = value; + } + + /// + /// Gets or sets the name. + /// + [DataMember(Name = "name")] + [JsonPropertyName("name")] + [Description("The item name.")] + public string Name + + { + get => GetCurrentProperty(); + set => SetCurrentProperty(value); + } + + /// + /// Gets or sets the value. + /// + [DataMember(Name = "value")] + [JsonPropertyName("value")] + [Description("The value.")] + public T Value + { + get => GetCurrentProperty(); + set => SetCurrentProperty(value); + } + + /// + /// Gets or sets the optional additional object. + /// + [JsonIgnore] + public object Tag + { + get => GetCurrentProperty(); + set => SetCurrentProperty(value); + } +} diff --git a/Core/Maths/Statistics/Average.cs b/Core/Maths/Statistics/Average.cs index 82f3234..d565b08 100644 --- a/Core/Maths/Statistics/Average.cs +++ b/Core/Maths/Statistics/Average.cs @@ -1,14 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2010 Nanchang Jinchen Software Co., Ltd. All rights reserved. -// -// -// The basic arithmetic functions. -// -// Kingcean Tuan -// -------------------------------------------------------------------------------------------------------------------- - -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/Core/Maths/Statistics/Difference.cs b/Core/Maths/Statistics/Difference.cs new file mode 100644 index 0000000..b8c11bc --- /dev/null +++ b/Core/Maths/Statistics/Difference.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Trivial.Maths; + +/// +/// The functions of probability theory and mathematical statistics. +/// +public static partial class StatisticalMethod +{ + /// + /// Gets a sequence about each item is different than before one of a specific numbers. + /// + /// The input numbers. + /// The increasement of each item. + public static IEnumerable Difference(IEnumerable col) + { + if (col == null) yield break; + double? test = null; + foreach (var item in col) + { + if (test.HasValue) yield return item - test.Value; + test = item; + } + } + + /// + /// Gets a sequence about each item is different than before one of a specific numbers. + /// + /// The input numbers. + /// The increasement of each item. + public static IEnumerable Difference(IEnumerable col) + { + if (col == null) yield break; + float? test = null; + foreach (var item in col) + { + if (test.HasValue) yield return item - test.Value; + test = item; + } + } + + /// + /// Gets a sequence about each item is different than before one of a specific numbers. + /// + /// The input numbers. + /// The increasement of each item. + public static IEnumerable Difference(IEnumerable col) + { + if (col == null) yield break; + decimal? test = null; + foreach (var item in col) + { + if (test.HasValue) yield return item - test.Value; + test = item; + } + } + + /// + /// Gets a sequence about each item is different than before one of a specific numbers. + /// + /// The input numbers. + /// The increasement of each item. + public static IEnumerable Difference(IEnumerable col) + { + if (col == null) yield break; + long? test = null; + foreach (var item in col) + { + if (test.HasValue) yield return item - test.Value; + test = item; + } + } + + /// + /// Gets a sequence about each item is different than before one of a specific numbers. + /// + /// The input numbers. + /// The increasement of each item. + public static IEnumerable Difference(IEnumerable col) + { + if (col == null) yield break; + int? test = null; + foreach (var item in col) + { + if (test.HasValue) yield return item - test.Value; + test = item; + } + } + + /// + /// Gets a sequence about each item is different than before one of a specific numbers. + /// + /// The input numbers. + /// The increasement of each item. + public static IEnumerable Difference(IEnumerable col) + { + if (col == null) yield break; + DateTime? test = null; + foreach (var item in col) + { + if (test.HasValue) yield return item - test.Value; + test = item; + } + } + + /// + /// Gets a sequence about each item is different than before one of a specific numbers. + /// + /// The input numbers. + /// The increasement of each item. + public static IEnumerable Difference(IEnumerable col) + { + if (col == null) yield break; + TimeSpan? test = null; + foreach (var item in col) + { + if (test.HasValue) yield return item - test.Value; + test = item; + } + } +} diff --git a/Core/Reflection/Lifecycle/ObservableProperties.cs b/Core/Reflection/Lifecycle/ObservableProperties.cs index 9150e53..754b4ef 100644 --- a/Core/Reflection/Lifecycle/ObservableProperties.cs +++ b/Core/Reflection/Lifecycle/ObservableProperties.cs @@ -92,7 +92,7 @@ protected T GetCurrentProperty(T defaultValue = default, [CallerMemberName] s if (string.IsNullOrWhiteSpace(key)) return defaultValue; try { - return cache.TryGetValue(key, out var v) ? (T)v : defaultValue; + return TryGetPropertyInternal(key, out var v) ? (T)v : defaultValue; } catch (InvalidCastException) { @@ -146,7 +146,7 @@ protected T GetProperty(string key, T defaultValue = default) if (string.IsNullOrWhiteSpace(key)) return defaultValue; try { - return cache.TryGetValue(key, out var v) && v is T t ? t : defaultValue; + return TryGetPropertyInternal(key, out var v) && v is T t ? t : defaultValue; } catch (InvalidOperationException) { @@ -175,7 +175,7 @@ protected bool GetProperty(string key, out T result) { try { - if (!string.IsNullOrWhiteSpace(key) && cache.TryGetValue(key, out var v) && v is T t) + if (!string.IsNullOrWhiteSpace(key) && TryGetPropertyInternal(key, out var v) && v is T t) { result = t; return true; @@ -226,7 +226,7 @@ protected bool SetProperty(string key, object value) } /// - /// Test whether the new property to set is valid. + /// Tests whether the new property to set is valid. /// /// The property key. /// The value of the property to set. @@ -234,6 +234,18 @@ protected bool SetProperty(string key, object value) protected virtual bool IsPropertyValid(string key, object value) => true; + /// + /// Occurs on request to get a specific value. This can be used to fill a default value. + /// + /// The property key. + /// When this method returns, contains the value associated with the specified key, if the key is found; otherwise, the default value for the type of the value parameter. This parameter is passed uninitialized. + /// true if need to set a default value; otherwise, false. + protected virtual bool FillNonExistProperty(string key, out object value) + { + value = default; + return false; + } + /// /// Removes a property. /// @@ -269,7 +281,7 @@ protected Type GetPropertyType(string key) if (string.IsNullOrWhiteSpace(key)) return null; try { - return cache.TryGetValue(key, out var v) ? v?.GetType() : null; + return TryGetPropertyInternal(key, out var v) ? v?.GetType() : null; } catch (ArgumentException) { @@ -352,6 +364,21 @@ protected void CopyFrom(BaseObservableProperties props, bool skipIfExist = false protected IEnumerator> EnumerateObject() => cache.GetEnumerator(); + /// + /// Tries to get property. + /// + /// The property key. + /// When this method returns, contains the value associated with the specified key, if the key is found; otherwise, the default value for the type of the value parameter. This parameter is passed uninitialized. + /// true if the cache contains an element with the specified key; otherwise, false. + private bool TryGetPropertyInternal(string key, out object value) + { + if (cache.TryGetValue(key, out value)) return true; + if (!FillNonExistProperty(key, out value)) return false; + cache[key] = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(key)); + return true; + } + /// /// Sets the property. /// diff --git a/Core/Text/Json/Converter.cs b/Core/Text/Json/Converter.cs index ac18a89..5d11307 100644 --- a/Core/Text/Json/Converter.cs +++ b/Core/Text/Json/Converter.cs @@ -61,6 +61,32 @@ public sealed class SemicolonSeparatedConverter : JsonStringListConverter } } + /// + /// JSON string collection with enumeration comma separated. + /// + public sealed class EnumerationCommaSeparatedConverter : JsonStringListConverter + { + /// + /// Initializes a new instance of the EnumerationCommaSeparatedConverter class. + /// + public EnumerationCommaSeparatedConverter() : base('、') + { + } + } + + /// + /// JSON string collection with semicolon separated. + /// + public sealed class ChineseSemicolonSeparatedConverter : JsonStringListConverter + { + /// + /// Initializes a new instance of the SemicolonSeparatedConverter class. + /// + public ChineseSemicolonSeparatedConverter() : base(';') + { + } + } + /// /// JSON string collection with vertical bar separated. /// @@ -126,7 +152,7 @@ public override IEnumerable Read(ref Utf8JsonReader reader, Type typeToC { IEnumerable arr = str.Split(chars, StringSplitOptions.RemoveEmptyEntries); if (trim) arr = arr.Select(ele => ele.Trim()).Where(ele => ele.Length > 0); - else col.AddRange(arr); + col.AddRange(arr); } else { diff --git a/UnitTest/Reflection/SingletonUnitTest.cs b/UnitTest/Reflection/SingletonUnitTest.cs index f299e7a..39fe169 100644 --- a/UnitTest/Reflection/SingletonUnitTest.cs +++ b/UnitTest/Reflection/SingletonUnitTest.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Trivial.Data; using Trivial.Text; namespace Trivial.Reflection @@ -44,7 +45,7 @@ public async Task TestSingletonKeeperAsync() public void TestObservableProperties() { var i = 0; - var obs = new NameValueObservableProperties(); + var obs = new NameValueObservableModel(); obs.PropertyChanged += (sender, obj) => { if (obj.PropertyName == "Value") i++; @@ -57,8 +58,18 @@ public void TestObservableProperties() Assert.AreEqual(1, i); obs.Value = "uvwxyz"; Assert.AreEqual(2, i); + var m = JsonSerializer.Deserialize("{ \"id\": \"9876543210\", \"keywords\": \"test;another\" }"); + Assert.AreEqual("9876543210", m.Id); + Assert.IsNull(m.Title); + Assert.IsNotNull(m.Keywords); + Assert.AreEqual(2, m.Keywords.Count); + m = JsonSerializer.Deserialize("{ \"id\": \"9876543210\", \"keywords\": [\"test\", \"another\"] }"); + Assert.AreEqual("9876543210", m.Id); + Assert.IsNull(m.Title); + Assert.IsNotNull(m.Keywords); + Assert.AreEqual(2, m.Keywords.Count); } - + /// /// Tests factory. ///