This commit is contained in:
Jack Kanarish
2018-02-21 14:12:35 -05:00
12 changed files with 478 additions and 52 deletions

View File

@@ -374,6 +374,29 @@ namespace ICD.Common.Utils.Tests.Extensions
Assert.AreEqual("C", values[2]);
}
[Test]
public void DistinctTest()
{
string[] items =
{
"one",
"two",
"three"
};
items = items.Distinct(i => i.Length).ToArray();
Assert.AreEqual(2, items.Length);
Assert.AreEqual("one", items[0]);
Assert.AreEqual("three", items[1]);
}
[Test]
public void DistinctComparerTest()
{
Assert.Inconclusive();
}
[Test]
public void UnanimousTest()
{

View File

@@ -1,4 +1,10 @@
using NUnit.Framework;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using ICD.Common.Utils.Extensions;
using Newtonsoft.Json;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Extensions
{
@@ -34,5 +40,91 @@ namespace ICD.Common.Utils.Tests.Extensions
{
Assert.Inconclusive();
}
[Test]
public void SerializeArrayTest()
{
JsonSerializer serializer = new JsonSerializer();
StringBuilder stringBuilder = new StringBuilder();
using (StringWriter stringWriter = new StringWriter(stringBuilder))
{
using (JsonWriter writer = new JsonTextWriter(stringWriter))
{
serializer.SerializeArray(writer, new int[] {1, 2, 3, 4});
}
}
string json = stringBuilder.ToString();
Assert.AreEqual("[1,2,3,4]", json);
}
[Test]
public void DeserializeArrayTest()
{
const string json = "[1,2,3,4]";
JsonSerializer serializer = new JsonSerializer();
int[] deserialized;
using (StringReader stringReader = new StringReader(json))
{
using (JsonReader reader = new JsonTextReader(stringReader))
{
reader.Read();
deserialized = serializer.DeserializeArray<int>(reader).ToArray();
}
}
Assert.IsTrue(deserialized.SequenceEqual(new int[] {1, 2, 3, 4}));
}
[Test]
public void SerializeDictionaryTest()
{
Dictionary<int, string> dict = new Dictionary<int, string>
{
{1, "Item 1"},
{10, "Item 2"},
{15, "Item 3"}
};
JsonSerializer serializer = new JsonSerializer();
StringBuilder stringBuilder = new StringBuilder();
using (StringWriter stringWriter = new StringWriter(stringBuilder))
{
using (JsonWriter writer = new JsonTextWriter(stringWriter))
{
serializer.SerializeDictionary(writer, dict);
}
}
string json = stringBuilder.ToString();
Assert.AreEqual("{\"1\":\"Item 1\",\"10\":\"Item 2\",\"15\":\"Item 3\"}", json);
}
[Test]
public void DeserializeDictionaryTest()
{
const string json = "{\"1\":\"Item 1\",\"10\":\"Item 2\",\"15\":\"Item 3\"}";
JsonSerializer serializer = new JsonSerializer();
Dictionary<int, string> deserialized;
using (StringReader stringReader = new StringReader(json))
{
using (JsonReader reader = new JsonTextReader(stringReader))
{
reader.Read();
deserialized = serializer.DeserializeDictionary<int, string>(reader).ToDictionary();
}
}
Assert.AreEqual(3, deserialized.Count);
Assert.AreEqual("Item 1", deserialized[1]);
Assert.AreEqual("Item 2", deserialized[10]);
Assert.AreEqual("Item 3", deserialized[15]);
}
}
}

View File

@@ -0,0 +1,13 @@
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Json
{
public abstract class AbstractGenericJsonConverterTest
{
[Test]
public abstract void WriteJsonTest();
[Test]
public abstract void ReadJsonTest();
}
}

View File

@@ -653,23 +653,51 @@ namespace ICD.Common.Utils.Extensions
}
/// <summary>
/// Gets distinct elements from the sequence based on given callbacks.
/// Gets distinct elements from the sequence based on given property.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TItem"></typeparam>
/// <typeparam name="TProperty"></typeparam>
/// <param name="extends"></param>
/// <param name="comparer"></param>
/// <param name="getHashCode"></param>
/// <param name="getProperty"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<T> Distinct<T>(this IEnumerable<T> extends, Func<T, T, bool> comparer, Func<T, int> getHashCode)
public static IEnumerable<TItem> Distinct<TItem, TProperty>(this IEnumerable<TItem> extends,
Func<TItem, TProperty> getProperty)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (comparer == null)
throw new ArgumentNullException("comparer");
if (getProperty == null)
throw new ArgumentNullException("getProperty");
return extends.Distinct(new FuncComparer<T>(comparer, getHashCode));
IEqualityComparer<TProperty> comparer = EqualityComparer<TProperty>.Default;
return extends.Distinct(getProperty, comparer);
}
/// <summary>
/// Gets distinct elements from the sequence based on given property.
/// </summary>
/// <typeparam name="TItem"></typeparam>
/// <typeparam name="TProperty"></typeparam>
/// <param name="extends"></param>
/// <param name="getProperty"></param>
/// <param name="propertyComparer"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<TItem> Distinct<TItem, TProperty>(this IEnumerable<TItem> extends,
Func<TItem, TProperty> getProperty,
IEqualityComparer<TProperty> propertyComparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (getProperty == null)
throw new ArgumentNullException("getProperty");
if (propertyComparer == null)
throw new ArgumentNullException("propertyComparer");
return extends.Distinct(new PropertyEqualityComparer<TItem, TProperty>(propertyComparer, getProperty));
}
/// <summary>

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using ICD.Common.Properties;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -34,6 +35,44 @@ namespace ICD.Common.Utils.Extensions
jObject.WriteTo(extends, converter);
}
/// <summary>
/// Writes the type value.
/// </summary>
/// <param name="extends"></param>
/// <param name="type"></param>
[PublicAPI]
public static void WriteType(this JsonWriter extends, Type type)
{
if (extends == null)
throw new ArgumentNullException("extends");
string name;
if (type == null)
name = null;
else if (type.IsPrimitive)
name = type.Name;
else
name = type.AssemblyQualifiedName;
extends.WriteValue(name);
}
/// <summary>
/// Gets the current value as a Type.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static Type GetValueAsType(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
string value = extends.GetValueAsString();
return Type.GetType(value, false, true);
}
/// <summary>
/// Gets the current value as an integer.
/// </summary>
@@ -103,5 +142,183 @@ namespace ICD.Common.Utils.Extensions
return EnumUtils.Parse<T>(extends.GetValueAsString(), true);
return (T)(object)extends.GetValueAsInt();
}
/// <summary>
/// Serializes the given sequence of items to the writer.
/// </summary>
/// <typeparam name="TItem"></typeparam>
/// <param name="extends"></param>
/// <param name="writer"></param>
/// <param name="items"></param>
public static void SerializeArray<TItem>(this JsonSerializer extends, JsonWriter writer, IEnumerable<TItem> items)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (writer == null)
throw new ArgumentNullException("writer");
if (items == null)
throw new ArgumentNullException("items");
extends.SerializeArray(writer, items, (s, w, item) => s.Serialize(w, item));
}
/// <summary>
/// Serializes the given sequence of items to the writer.
/// </summary>
/// <typeparam name="TItem"></typeparam>
/// <param name="extends"></param>
/// <param name="writer"></param>
/// <param name="items"></param>
/// <param name="write"></param>
public static void SerializeArray<TItem>(this JsonSerializer extends, JsonWriter writer, IEnumerable<TItem> items,
Action<JsonSerializer, JsonWriter, TItem> write)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (writer == null)
throw new ArgumentNullException("writer");
if (items == null)
throw new ArgumentNullException("items");
if (write == null)
throw new ArgumentNullException("write");
writer.WriteStartArray();
{
foreach (TItem item in items)
write(extends, writer, item);
}
writer.WriteEndArray();
}
/// <summary>
/// Deserializes an array of items from the reader's current value.
/// </summary>
/// <typeparam name="TItem"></typeparam>
/// <param name="extends"></param>
/// <param name="reader"></param>
public static IEnumerable<TItem> DeserializeArray<TItem>(this JsonSerializer extends, JsonReader reader)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (reader == null)
throw new ArgumentNullException("reader");
return extends.DeserializeArray(reader, (s, r) => extends.Deserialize<TItem>(reader));
}
/// <summary>
/// Deserializes an array of items from the reader's current value.
/// </summary>
/// <typeparam name="TItem"></typeparam>
/// <param name="extends"></param>
/// <param name="reader"></param>
/// <param name="read"></param>
public static IEnumerable<TItem> DeserializeArray<TItem>(this JsonSerializer extends, JsonReader reader,
Func<JsonSerializer, JsonReader, TItem> read)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (reader == null)
throw new ArgumentNullException("reader");
if (read == null)
throw new ArgumentNullException("read");
if (reader.TokenType == JsonToken.Null)
yield break;
if (reader.TokenType != JsonToken.StartArray)
throw new FormatException(string.Format("Expected token {0} got {1}", JsonToken.StartArray, reader.TokenType));
// Step into the first value
reader.Read();
while (reader.TokenType != JsonToken.EndArray)
{
TItem output = read(extends, reader);
yield return output;
// Read out of the last value
reader.Read();
}
}
/// <summary>
/// Serializes the given sequence of key-value-pairs to the writer.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="writer"></param>
/// <param name="items"></param>
public static void SerializeDictionary<TKey, TValue>(this JsonSerializer extends, JsonWriter writer,
IEnumerable<KeyValuePair<TKey, TValue>> items)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (writer == null)
throw new ArgumentNullException("writer");
if (items == null)
throw new ArgumentNullException("items");
writer.WriteStartObject();
{
foreach (KeyValuePair<TKey, TValue> kvp in items)
{
writer.WritePropertyName(kvp.Key.ToString());
extends.Serialize(writer, kvp.Value);
}
}
writer.WriteEndObject();
}
/// <summary>
/// Deserializes a dictionary of items from the reader's current value.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="reader"></param>
public static IEnumerable<KeyValuePair<TKey, TValue>> DeserializeDictionary<TKey, TValue>(this JsonSerializer extends, JsonReader reader)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (reader == null)
throw new ArgumentNullException("reader");
if (reader.TokenType == JsonToken.Null)
yield break;
if (reader.TokenType != JsonToken.StartObject)
throw new FormatException(string.Format("Expected token {0} got {1}", JsonToken.StartObject, reader.TokenType));
// Step into the first key
reader.Read();
while (reader.TokenType != JsonToken.EndObject)
{
TKey key = (TKey)Convert.ChangeType(reader.Value, typeof(TKey), null);
// Step into the value
reader.Read();
TValue value = extends.Deserialize<TValue>(reader);
yield return new KeyValuePair<TKey, TValue>(key, value);
// Read out of the last value
reader.Read();
}
}
}
}

View File

@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
namespace ICD.Common.Utils.Extensions
{
/// <summary>
/// Allows for comparing items based on some property.
/// </summary>
/// <typeparam name="TParent"></typeparam>
/// <typeparam name="TProperty"></typeparam>
public sealed class PropertyEqualityComparer<TParent, TProperty> : IEqualityComparer<TParent>
{
private readonly IEqualityComparer<TProperty> m_Comparer;
private readonly Func<TParent, TProperty> m_GetProperty;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="comparer"></param>
/// <param name="getProperty"></param>
public PropertyEqualityComparer(IEqualityComparer<TProperty> comparer, Func<TParent, TProperty> getProperty)
{
m_Comparer = comparer;
m_GetProperty = getProperty;
}
public bool Equals(TParent x, TParent y)
{
TProperty a = m_GetProperty(x);
TProperty b = m_GetProperty(y);
return m_Comparer.Equals(a, b);
}
public int GetHashCode(TParent parent)
{
TProperty property = m_GetProperty(parent);
return m_Comparer.GetHashCode(property);
}
}
}

View File

@@ -42,7 +42,15 @@ namespace ICD.Common.Utils.Extensions
if (extends == null)
throw new ArgumentNullException("extends");
return extends.GetCustomAttributes(typeof(T), inherits).Cast<T>();
try
{
return extends.GetCustomAttributes(typeof(T), inherits).Cast<T>();
}
// Crestron bug?
catch (ArgumentNullException)
{
return Enumerable.Empty<T>();
}
}
/// <summary>

View File

@@ -1,36 +0,0 @@
using System;
using System.Collections.Generic;
namespace ICD.Common.Utils
{
/// <summary>
/// Simple comparer for comparing items using a callback.
/// </summary>
/// <typeparam name="T"></typeparam>
public sealed class FuncComparer<T> : IEqualityComparer<T>
{
private readonly Func<T, T, bool> m_Comparer;
private readonly Func<T, int> m_GetHashCode;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="comparer"></param>
/// <param name="getHashCode"></param>
public FuncComparer(Func<T, T, bool> comparer, Func<T, int> getHashCode)
{
m_Comparer = comparer;
m_GetHashCode = getHashCode;
}
public bool Equals(T x, T y)
{
return m_Comparer(x, y);
}
public int GetHashCode(T obj)
{
return m_GetHashCode(obj);
}
}
}

View File

@@ -87,7 +87,7 @@
<None Include="ObfuscationSettings.cs" />
<Compile Include="Extensions\ByteExtensions.cs" />
<Compile Include="Extensions\ListExtensions.cs" />
<Compile Include="FuncComparer.cs" />
<Compile Include="Extensions\PropertyEqualityComparer.cs" />
<Compile Include="ProcessorUtils.SimplSharp.cs" />
<Compile Include="ProcessorUtils.Standard.cs" />
<Compile Include="ProgramUtils.SimplSharp.cs" />

View File

@@ -45,9 +45,6 @@ namespace ICD.Common.Utils.Json
public sealed override object ReadJson(JsonReader reader, Type objectType, object existingValue,
JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
return ReadJson(reader, (T)existingValue, serializer);
}

View File

@@ -29,8 +29,16 @@ namespace ICD.Common.Utils.Json
public static void CacheType<T>()
where T : new()
{
string serialized = JsonConvert.SerializeObject(ReflectionUtils.CreateInstance<T>());
JsonConvert.DeserializeObject<T>(serialized);
CacheType(typeof(T));
}
/// <summary>
/// Forces Newtonsoft to cache the given type for faster subsequent usage.
/// </summary>
public static void CacheType(Type type)
{
string serialized = JsonConvert.SerializeObject(ReflectionUtils.CreateInstance(type));
JsonConvert.DeserializeObject(serialized, type);
}
/// <summary>

View File

@@ -210,6 +210,26 @@ namespace ICD.Common.Utils
: null;
}
/// <summary>
/// Returns true if the given type has a public parameterless constructor.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static bool HasPublicParameterlessConstructor(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
const BindingFlags binding = BindingFlags.Instance | BindingFlags.Public;
#if SIMPLSHARP
return ((CType)type).GetConstructor(binding, null, new CType[0], null)
#else
return type.GetConstructor(binding, null, new Type[0], null)
#endif
!= null;
}
/// <summary>
/// Creates an instance of the given type, calling the default constructor.
/// </summary>
@@ -240,6 +260,21 @@ namespace ICD.Common.Utils
}
}
/// <summary>
/// Creates an instance of the given type, calling the default constructor.
/// </summary>
/// <returns></returns>
public static T CreateInstance<T>(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
if (!type.IsAssignableTo(typeof(T)))
throw new InvalidOperationException("Type is not assignable to T");
return (T)CreateInstance(type);
}
/// <summary>
/// Gets the custom attributes added to the given assembly.
/// </summary>