This commit is contained in:
Jack Kanarish
2018-04-10 11:07:26 -04:00
11 changed files with 356 additions and 112 deletions

View File

@@ -10,6 +10,14 @@ namespace ICD.Common.Utils.Tests.Extensions
[TestFixture] [TestFixture]
public sealed class TypeExtensionsTest public sealed class TypeExtensionsTest
{ {
[TestCase(typeof(byte), false)]
[TestCase(typeof(byte?), true)]
[TestCase(typeof(string), true)]
public void CanBeNullTest(Type value, bool expected)
{
Assert.AreEqual(expected, value.CanBeNull());
}
[TestCase(typeof(byte), true)] [TestCase(typeof(byte), true)]
[TestCase(typeof(decimal), true)] [TestCase(typeof(decimal), true)]
[TestCase(typeof(double), true)] [TestCase(typeof(double), true)]
@@ -61,6 +69,23 @@ namespace ICD.Common.Utils.Tests.Extensions
Assert.AreEqual(expected, value.IsDecimalNumeric()); Assert.AreEqual(expected, value.IsDecimalNumeric());
} }
[TestCase(typeof(byte), true)]
[TestCase(typeof(decimal), false)]
[TestCase(typeof(double), false)]
[TestCase(typeof(float), false)]
[TestCase(typeof(int), true)]
[TestCase(typeof(long), true)]
[TestCase(typeof(sbyte), true)]
[TestCase(typeof(short), true)]
[TestCase(typeof(uint), true)]
[TestCase(typeof(ulong), true)]
[TestCase(typeof(ushort), true)]
[TestCase(typeof(string), false)]
public void IsIntegerNumericTest(Type value, bool expected)
{
Assert.AreEqual(expected, value.IsIntegerNumeric());
}
[TestCase(typeof(string), typeof(object), true)] [TestCase(typeof(string), typeof(object), true)]
[TestCase(typeof(object), typeof(string), false)] [TestCase(typeof(object), typeof(string), false)]
public void IsAssignableToTest(Type a, Type b, bool expected) public void IsAssignableToTest(Type a, Type b, bool expected)

View File

@@ -4,6 +4,7 @@
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework> <TargetFramework>netcoreapp2.0</TargetFramework>
<RootNamespace>ICD.Common.Utils.Tests</RootNamespace> <RootNamespace>ICD.Common.Utils.Tests</RootNamespace>
<AssemblyName>ICD.Common.Utils.Tests</AssemblyName>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<Deterministic>true</Deterministic> <Deterministic>true</Deterministic>
</PropertyGroup> </PropertyGroup>
@@ -18,7 +19,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.6.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
<PackageReference Include="NUnit" Version="3.10.1" /> <PackageReference Include="NUnit" Version="3.10.1" />
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
</ItemGroup> </ItemGroup>

View File

@@ -34,23 +34,12 @@ namespace ICD.Common.Utils.Tests
} }
} }
[TestCase("test", 10)]
[TestCase(null, 0)]
public void InstantiateTest(string param1, int param2)
{
TestClass result = ReflectionUtils.Instantiate(typeof(TestClass), param1, param2) as TestClass;
Assert.NotNull(result);
Assert.AreEqual(param1, result.Param1);
Assert.AreEqual(param2, result.Param2);
}
[Test] [Test]
public void MatchesConstructorParametersTest() public void MatchesConstructorParametersTest()
{ {
Assert.Throws<ArgumentNullException>(() => ReflectionUtils.MatchesConstructorParameters(null, new object[] { "test", 10 })); Assert.Throws<ArgumentNullException>(() => ReflectionUtils.MatchesConstructorParameters(null, new object[] { "test", 10 }));
ConstructorInfo constructor = typeof(TestClass).GetConstructor(new Type[] {typeof(string), typeof(int)}); ConstructorInfo constructor = typeof(TestClass).GetConstructor(new[] {typeof(string), typeof(int)});
Assert.IsTrue(ReflectionUtils.MatchesConstructorParameters(constructor, new object[] {"test", 10})); Assert.IsTrue(ReflectionUtils.MatchesConstructorParameters(constructor, new object[] {"test", 10}));
Assert.IsTrue(ReflectionUtils.MatchesConstructorParameters(constructor, new object[] {null, 10})); Assert.IsTrue(ReflectionUtils.MatchesConstructorParameters(constructor, new object[] {null, 10}));
@@ -114,6 +103,17 @@ namespace ICD.Common.Utils.Tests
Assert.NotNull(output); Assert.NotNull(output);
} }
[TestCase("test", 10)]
[TestCase(null, 0)]
public void CreateInstanceTest(string param1, int param2)
{
TestClass result = ReflectionUtils.CreateInstance(typeof(TestClass), param1, param2) as TestClass;
Assert.NotNull(result);
Assert.AreEqual(param1, result.Param1);
Assert.AreEqual(param2, result.Param2);
}
[Test] [Test]
public void GetCustomAttributesTest() public void GetCustomAttributesTest()
{ {
@@ -121,9 +121,33 @@ namespace ICD.Common.Utils.Tests
} }
[Test] [Test]
public void LoadAssemblyFromPath() public void LoadAssemblyFromPathTest()
{ {
Assert.Inconclusive(); Assert.Inconclusive();
} }
[Test]
public void GetImplementationTest()
{
Assert.Inconclusive();
}
[Test]
public void ChangeTypeTest()
{
// Same type
Assert.AreEqual(10, ReflectionUtils.ChangeType(10, typeof(int)));
// Null
Assert.AreEqual(null, ReflectionUtils.ChangeType(null, typeof(string)));
// Enums
Assert.AreEqual(BindingFlags.GetProperty, ReflectionUtils.ChangeType((int)(object)BindingFlags.GetProperty, typeof(BindingFlags)));
Assert.AreEqual(BindingFlags.GetProperty, ReflectionUtils.ChangeType(BindingFlags.GetProperty.ToString(), typeof(BindingFlags)));
Assert.AreEqual(BindingFlags.GetProperty, ReflectionUtils.ChangeType(((int)(object)BindingFlags.GetProperty).ToString(), typeof(BindingFlags)));
// Everything else
Assert.AreEqual(10, ReflectionUtils.ChangeType("10", typeof(int)));
}
} }
} }

View File

@@ -1062,12 +1062,14 @@ namespace ICD.Common.Utils.Extensions
{ {
public readonly T value; public readonly T value;
public readonly bool isParsed; public readonly bool isParsed;
public TryParseStruct(T value, bool isParsed) public TryParseStruct(T value, bool isParsed)
{ {
this.value = value; this.value = value;
this.isParsed = isParsed; this.isParsed = isParsed;
} }
} }
// since Func<...,T> can't specify `out` parameters // since Func<...,T> can't specify `out` parameters
public delegate bool TryParseDelegate<T>(string input, out T output); public delegate bool TryParseDelegate<T>(string input, out T output);
@@ -1079,7 +1081,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends">enumerable of strings to parse</param> /// <param name="extends">enumerable of strings to parse</param>
/// <param name="tryParseFunc">TryParse function for given type</param> /// <param name="tryParseFunc">TryParse function for given type</param>
/// <returns>enumerable of successfully parsed values</returns> /// <returns>enumerable of successfully parsed values</returns>
public static IEnumerable<T> TryParseSkipFailures<T>(this IEnumerable<string> extends, TryParseDelegate<T> tryParseFunc) public static IEnumerable<T> TryParseSkipFailures<T>(this IEnumerable<string> extends,
TryParseDelegate<T> tryParseFunc)
{ {
if (extends == null) if (extends == null)
throw new ArgumentNullException("extends"); throw new ArgumentNullException("extends");
@@ -1088,13 +1091,13 @@ namespace ICD.Common.Utils.Extensions
throw new ArgumentNullException("tryParseFunc"); throw new ArgumentNullException("tryParseFunc");
return extends.Select(str => return extends.Select(str =>
{ {
T value = default(T); T value;
bool isParsed = tryParseFunc(str, out value); bool isParsed = tryParseFunc(str, out value);
return new TryParseStruct<T>(value, isParsed); return new TryParseStruct<T>(value, isParsed);
}) })
.Where(v => v.isParsed == true) .Where(v => v.isParsed)
.Select(v => v.value); .Select(v => v.value);
} }
#if SIMPLSHARP #if SIMPLSHARP

View File

@@ -45,6 +45,18 @@ namespace ICD.Common.Utils.Extensions
typeof(float), typeof(float),
}; };
private static readonly IcdHashSet<Type> s_IntegerNumericTypes = new IcdHashSet<Type>
{
typeof(byte),
typeof(int),
typeof(long),
typeof(sbyte),
typeof(short),
typeof(uint),
typeof(ulong),
typeof(ushort)
};
private static readonly Dictionary<Type, Type[]> s_TypeAllTypes; private static readonly Dictionary<Type, Type[]> s_TypeAllTypes;
private static readonly Dictionary<Type, Type[]> s_TypeBaseTypes; private static readonly Dictionary<Type, Type[]> s_TypeBaseTypes;
private static readonly Dictionary<Type, Type[]> s_TypeImmediateInterfaces; private static readonly Dictionary<Type, Type[]> s_TypeImmediateInterfaces;
@@ -61,6 +73,19 @@ namespace ICD.Common.Utils.Extensions
s_TypeMinimalInterfaces = new Dictionary<Type, Type[]>(); s_TypeMinimalInterfaces = new Dictionary<Type, Type[]>();
} }
/// <summary>
/// Returns true if the given type can represent a null value.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static bool CanBeNull(this Type extends)
{
if (extends == null)
throw new ArgumentException("extends");
return !extends.IsValueType || Nullable.GetUnderlyingType(extends) != null;
}
/// <summary> /// <summary>
/// Returns true if the given type is a numeric type. /// Returns true if the given type is a numeric type.
/// </summary> /// </summary>
@@ -100,6 +125,24 @@ namespace ICD.Common.Utils.Extensions
return s_DecimalNumericTypes.Contains(extends); return s_DecimalNumericTypes.Contains(extends);
} }
/// <summary>
/// Returns true if the given type is an integer numeric type.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static bool IsIntegerNumeric(this Type extends)
{
if (extends == null)
throw new ArgumentException("extends");
return s_IntegerNumericTypes.Contains(extends);
}
/// <summary>
/// Gets the Assembly containing the type.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static Assembly GetAssembly(this Type extends) public static Assembly GetAssembly(this Type extends)
{ {
if (extends == null) if (extends == null)
@@ -114,6 +157,12 @@ namespace ICD.Common.Utils.Extensions
.Assembly; .Assembly;
} }
/// <summary>
/// Returns true if the type is assignable to the given type.
/// </summary>
/// <param name="from"></param>
/// <param name="to"></param>
/// <returns></returns>
public static bool IsAssignableTo(this Type from, Type to) public static bool IsAssignableTo(this Type from, Type to)
{ {
if (from == null) if (from == null)

View File

@@ -5,8 +5,8 @@
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>ICD.Common.Utils</AssemblyName> <AssemblyName>ICD.Common.Utils</AssemblyName>
<RootNamespace>$(AssemblyName)</RootNamespace> <RootNamespace>$(AssemblyName)</RootNamespace>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<Deterministic>true</Deterministic> <Deterministic>true</Deterministic>
<Authors>Chris Cameron, Jeff Thompson</Authors> <Authors>Chris Cameron, Jeff Thompson</Authors>
<PackageId>ICD.Common.Utils</PackageId> <PackageId>ICD.Common.Utils</PackageId>
<PackageProjectUrl></PackageProjectUrl> <PackageProjectUrl></PackageProjectUrl>
@@ -44,7 +44,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Data.SQLite" Version="2.0.1" /> <PackageReference Include="Microsoft.Data.SQLite" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="2.0.4" /> <PackageReference Include="Microsoft.Extensions.DependencyModel" Version="2.0.4" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" /> <PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" />
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" /> <PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
</ItemGroup> </ItemGroup>

View File

@@ -8,7 +8,7 @@
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ICD.Common.Utils</RootNamespace> <RootNamespace>ICD.Common.Utils</RootNamespace>
<AssemblyName>ICD.Common.Utils_SimplSharp</AssemblyName> <AssemblyName>ICD.Common.Utils</AssemblyName>
<ProjectTypeGuids>{0B4745B0-194B-4BB6-8E21-E9057CA92500};{4D628B5B-2FBC-4AA6-8C16-197242AEB884};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> <ProjectTypeGuids>{0B4745B0-194B-4BB6-8E21-E9057CA92500};{4D628B5B-2FBC-4AA6-8C16-197242AEB884};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<PlatformFamilyName>WindowsCE</PlatformFamilyName> <PlatformFamilyName>WindowsCE</PlatformFamilyName>
<PlatformID>E2BECB1F-8C8C-41ba-B736-9BE7D946A398</PlatformID> <PlatformID>E2BECB1F-8C8C-41ba-B736-9BE7D946A398</PlatformID>

View File

@@ -14,6 +14,12 @@ namespace ICD.Common.Utils.Json
/// <param name="serializer">The calling serializer.</param> /// <param name="serializer">The calling serializer.</param>
public sealed override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) public sealed override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{ {
if (writer == null)
throw new ArgumentNullException("writer");
if (serializer == null)
throw new ArgumentNullException("serializer");
if (value == null) if (value == null)
{ {
writer.WriteNull(); writer.WriteNull();
@@ -45,6 +51,12 @@ namespace ICD.Common.Utils.Json
public sealed override object ReadJson(JsonReader reader, Type objectType, object existingValue, public sealed override object ReadJson(JsonReader reader, Type objectType, object existingValue,
JsonSerializer serializer) JsonSerializer serializer)
{ {
if (reader == null)
throw new ArgumentNullException("reader");
if (serializer == null)
throw new ArgumentNullException("serializer");
return ReadJson(reader, (T)existingValue, serializer); return ReadJson(reader, (T)existingValue, serializer);
} }

View File

@@ -37,6 +37,9 @@ namespace ICD.Common.Utils.Json
/// </summary> /// </summary>
public static void CacheType(Type type) public static void CacheType(Type type)
{ {
if (type == null)
throw new ArgumentNullException("type");
string serialized = JsonConvert.SerializeObject(ReflectionUtils.CreateInstance(type)); string serialized = JsonConvert.SerializeObject(ReflectionUtils.CreateInstance(type));
JsonConvert.DeserializeObject(serialized, type); JsonConvert.DeserializeObject(serialized, type);
} }
@@ -91,7 +94,34 @@ namespace ICD.Common.Utils.Json
[PublicAPI] [PublicAPI]
public static void Print(string json) public static void Print(string json)
{ {
IcdConsole.PrintLine(Format(json)); if (json == null)
throw new ArgumentNullException("json");
string formatted = Format(json);
IcdConsole.PrintLine(formatted);
}
/// <summary>
/// Serializes the given item and pretty-prints to JSON.
/// </summary>
/// <param name="value"></param>
[PublicAPI]
public static void Print(object value)
{
string formatted = Format(value);
IcdConsole.PrintLine(formatted);
}
/// <summary>
/// Serializes the given item and formats the JSON into a human-readable form.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
[PublicAPI]
public static string Format(object value)
{
string serial = JsonConvert.SerializeObject(value);
return Format(serial);
} }
/// <summary> /// <summary>
@@ -102,6 +132,9 @@ namespace ICD.Common.Utils.Json
[PublicAPI] [PublicAPI]
public static string Format(string json) public static string Format(string json)
{ {
if (json == null)
throw new ArgumentNullException("json");
int indent = 0; int indent = 0;
bool quoted = false; bool quoted = false;
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@@ -287,6 +320,12 @@ namespace ICD.Common.Utils.Json
/// <returns></returns> /// <returns></returns>
public static object Deserialize(Type type, JToken token) public static object Deserialize(Type type, JToken token)
{ {
if (type == null)
throw new ArgumentNullException("type");
if (token == null)
throw new ArgumentNullException("token");
return Deserialize(type, token, new JsonSerializer()); return Deserialize(type, token, new JsonSerializer());
} }
@@ -299,6 +338,15 @@ namespace ICD.Common.Utils.Json
/// <returns></returns> /// <returns></returns>
public static object Deserialize(Type type, JToken token, JsonSerializer serializer) public static object Deserialize(Type type, JToken token, JsonSerializer serializer)
{ {
if (type == null)
throw new ArgumentNullException("type");
if (token == null)
throw new ArgumentNullException("token");
if (serializer == null)
throw new ArgumentNullException("serializer");
using (JTokenReader jsonReader = new JTokenReader(token)) using (JTokenReader jsonReader = new JTokenReader(token))
return serializer.Deserialize(jsonReader, type); return serializer.Deserialize(jsonReader, type);
} }

View File

@@ -71,6 +71,9 @@ namespace ICD.Common.Utils
/// <returns>The newly mapped value</returns> /// <returns>The newly mapped value</returns>
public static double MapRange(double inputStart, double inputEnd, double outputStart, double outputEnd, double value) public static double MapRange(double inputStart, double inputEnd, double outputStart, double outputEnd, double value)
{ {
if (inputStart.Equals(inputEnd))
throw new DivideByZeroException();
double slope = (outputEnd - outputStart) / (inputEnd - inputStart); double slope = (outputEnd - outputStart) / (inputEnd - inputStart);
return outputStart + slope * (value - inputStart); return outputStart + slope * (value - inputStart);
} }

View File

@@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions; using ICD.Common.Utils.Extensions;
using ICD.Common.Utils.IO; using ICD.Common.Utils.IO;
#if SIMPLSHARP #if SIMPLSHARP
@@ -20,41 +19,6 @@ namespace ICD.Common.Utils
{ {
public static class ReflectionUtils public static class ReflectionUtils
{ {
/// <summary>
/// Instantiates the given type using the constructor matching the given values.
/// </summary>
/// <param name="type"></param>
/// <param name="values"></param>
/// <returns></returns>
[PublicAPI]
public static object Instantiate(Type type, params object[] values)
{
if (type == null)
throw new ArgumentNullException("type");
ConstructorInfo constructor =
#if SIMPLSHARP
((CType)type)
#else
type
#endif
.GetConstructors()
.FirstOrDefault(c => MatchesConstructorParameters(c, values));
try
{
if (constructor != null)
return constructor.Invoke(values);
}
catch (TypeLoadException e)
{
throw new TypeLoadException(e.GetBaseException().Message);
}
string message = string.Format("Unable to find constructor for {0}", type.Name);
throw new InvalidOperationException(message);
}
/// <summary> /// <summary>
/// Returns true if the parameters match the constructor parameters. /// Returns true if the parameters match the constructor parameters.
/// </summary> /// </summary>
@@ -70,12 +34,13 @@ namespace ICD.Common.Utils
throw new ArgumentNullException("parameters"); throw new ArgumentNullException("parameters");
#if SIMPLSHARP #if SIMPLSHARP
IEnumerable<CType> methodTypes IEnumerable<CType>
#else #else
IEnumerable<Type> methodTypes IEnumerable<Type>
#endif #endif
= constructor.GetParameters().Select(p => p.ParameterType); parameterTypes = constructor.GetParameters().Select(p => p.ParameterType);
return ParametersMatchTypes(methodTypes, parameters);
return ParametersMatchTypes(parameterTypes, parameters);
} }
/// <summary> /// <summary>
@@ -93,12 +58,13 @@ namespace ICD.Common.Utils
throw new ArgumentNullException("parameters"); throw new ArgumentNullException("parameters");
#if SIMPLSHARP #if SIMPLSHARP
IEnumerable<CType> methodTypes IEnumerable<CType>
#else #else
IEnumerable<Type> methodTypes IEnumerable<Type>
#endif #endif
= method.GetParameters().Select(p => p.ParameterType); parameterTypes = method.GetParameters().Select(p => p.ParameterType);
return ParametersMatchTypes(methodTypes, parameters);
return ParametersMatchTypes(parameterTypes, parameters);
} }
/// <summary> /// <summary>
@@ -113,11 +79,12 @@ namespace ICD.Common.Utils
throw new ArgumentNullException("property"); throw new ArgumentNullException("property");
#if SIMPLSHARP #if SIMPLSHARP
CType propertyType CType
#else #else
Type propertyType Type
#endif #endif
= property.PropertyType; propertyType = property.PropertyType;
return ParametersMatchTypes(new[] {propertyType}, new[] {parameter}); return ParametersMatchTypes(new[] {propertyType}, new[] {parameter});
} }
@@ -127,31 +94,41 @@ namespace ICD.Common.Utils
/// <param name="types"></param> /// <param name="types"></param>
/// <param name="parameters"></param> /// <param name="parameters"></param>
/// <returns></returns> /// <returns></returns>
private static bool ParametersMatchTypes(
#if SIMPLSHARP #if SIMPLSHARP
private static bool ParametersMatchTypes(IEnumerable<CType> types, IEnumerable<object> parameters) IEnumerable<CType>
{ #else
if (types == null) IEnumerable<Type>
throw new ArgumentNullException("types");
CType[] typesArray = types as CType[] ?? types.ToArray();
#else
private static bool ParametersMatchTypes(IEnumerable<Type> types, IEnumerable<object> parameters)
{
if (types == null)
throw new ArgumentNullException("types");
Type[] typesArray = types as Type[] ?? types.ToArray();
#endif #endif
types, IEnumerable<object> parameters)
{
if (types == null)
throw new ArgumentNullException("types");
if (parameters == null) if (parameters == null)
throw new ArgumentNullException("parameters"); throw new ArgumentNullException("parameters");
#if SIMPLSHARP
CType[]
#else
Type[]
#endif
typesArray = types as
#if SIMPLSHARP
CType[]
#else
Type[]
#endif
?? types.ToArray();
object[] parametersArray = parameters as object[] ?? parameters.ToArray(); object[] parametersArray = parameters as object[] ?? parameters.ToArray();
if (parametersArray.Length != typesArray.Length) if (parametersArray.Length != typesArray.Length)
return false; return false;
// Compares each pair of items in the two arrays. // Compares each pair of items in the two arrays.
return !parametersArray.Where((t, index) => !ParameterMatchesType(typesArray[index], t)).Any(); return !parametersArray.Where((t, index) => !ParameterMatchesType(typesArray[index], t))
.Any();
} }
/// <summary> /// <summary>
@@ -160,50 +137,38 @@ namespace ICD.Common.Utils
/// <param name="type"></param> /// <param name="type"></param>
/// <param name="parameter"></param> /// <param name="parameter"></param>
/// <returns></returns> /// <returns></returns>
#if SIMPLSHARP private static bool ParameterMatchesType(Type type, object parameter)
private static bool ParameterMatchesType(CType type, object parameter)
{ {
if (type == null) if (type == null)
throw new ArgumentNullException("type"); throw new ArgumentNullException("type");
#if SIMPLSHARP
// Can the parameter be assigned a null value? // Can the parameter be assigned a null value?
if (parameter == null) if (parameter == null)
return (type.IsClass || !type.IsValueType || Nullable.GetUnderlyingType(type) != null); return (type.IsClass || !type.IsValueType || Nullable.GetUnderlyingType(type) != null);
return type.IsInstanceOfType(parameter); return type.IsInstanceOfType(parameter);
}
#else #else
private static bool ParameterMatchesType(Type type, object parameter) TypeInfo info = type.GetTypeInfo();
{
if (type == null)
throw new ArgumentNullException("type");
TypeInfo info = type.GetTypeInfo();
// Can the parameter be assigned a null value? // Can the parameter be assigned a null value?
if (parameter == null) if (parameter == null)
return (info.IsClass || !info.IsValueType || Nullable.GetUnderlyingType(type) != null); return (info.IsClass || !info.IsValueType || Nullable.GetUnderlyingType(type) != null);
return info.IsInstanceOfType(parameter); return info.IsInstanceOfType(parameter);
}
#endif #endif
}
/// <summary> /// <summary>
/// Same as doing default(Type). /// Same as doing default(Type).
/// </summary> /// </summary>
/// <param name="type"></param> /// <param name="type"></param>
/// <returns></returns> /// <returns></returns>
#if SIMPLSHARP
public static object GetDefaultValue(CType type)
#else
public static object GetDefaultValue(Type type) public static object GetDefaultValue(Type type)
#endif
{ {
if (type == null) if (type == null)
throw new ArgumentNullException("type"); throw new ArgumentNullException("type");
return type return type
#if !SIMPLSHARP #if !SIMPLSHARP
.GetTypeInfo() .GetTypeInfo()
#endif #endif
.IsValueType .IsValueType
? Activator.CreateInstance(type) ? Activator.CreateInstance(type)
@@ -230,34 +195,69 @@ namespace ICD.Common.Utils
!= null; != null;
} }
/// <summary>
/// Platform independant delegate instantiation.
/// </summary>
/// <param name="type"></param>
/// <param name="firstArgument"></param>
/// <param name="method"></param>
/// <returns></returns>
public static Delegate CreateDelegate(Type type, object firstArgument, MethodInfo method)
{
return
#if SIMPLSHARP
CDelegate
#else
Delegate
#endif
.CreateDelegate(type, firstArgument, method);
}
/// <summary> /// <summary>
/// Creates an instance of the given type, calling the default constructor. /// Creates an instance of the given type, calling the default constructor.
/// </summary> /// </summary>
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
/// <returns></returns> /// <returns></returns>
public static T CreateInstance<T>() public static T CreateInstance<T>(params object[] parameters)
where T : new()
{ {
return (T)CreateInstance(typeof(T)); if (parameters == null)
throw new ArgumentNullException("parameters");
return (T)CreateInstance(typeof(T), parameters);
} }
/// <summary> /// <summary>
/// Creates an instance of the given type, calling the default constructor. /// Creates an instance of the given type, calling the default constructor.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public static object CreateInstance(Type type) public static object CreateInstance(Type type, params object[] parameters)
{ {
if (type == null) if (type == null)
throw new ArgumentNullException("type"); throw new ArgumentNullException("type");
if (parameters == null)
throw new ArgumentNullException("parameters");
ConstructorInfo constructor =
type
#if SIMPLSHARP
.GetCType()
#endif
.GetConstructors()
.FirstOrDefault(c => MatchesConstructorParameters(c, parameters));
try try
{ {
return Activator.CreateInstance(type); if (constructor != null)
return constructor.Invoke(parameters);
} }
catch (TargetInvocationException e) catch (TypeLoadException e)
{ {
throw e.GetBaseException(); throw new TypeLoadException(e.GetBaseException().Message);
} }
string message = string.Format("Unable to find constructor for {0}", type.Name);
throw new InvalidOperationException(message);
} }
/// <summary> /// <summary>
@@ -335,5 +335,84 @@ namespace ICD.Common.Utils
: AssemblyLoadContext.Default.LoadFromAssemblyPath(path); : AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
#endif #endif
} }
/// <summary>
/// Finds the corresponding property info on the given type.
/// </summary>
/// <param name="type"></param>
/// <param name="property"></param>
/// <returns></returns>
public static PropertyInfo GetImplementation(Type type, PropertyInfo property)
{
if (type == null)
throw new ArgumentNullException("type");
if (property == null)
throw new ArgumentNullException("property");
if (type.IsInterface)
throw new InvalidOperationException("Type must not be an interface");
property = type
#if SIMPLSHARP
.GetCType()
#else
.GetTypeInfo()
#endif
.GetProperty(property.Name, property.PropertyType);
if (property == null)
return null;
return property.DeclaringType == type
? property
: GetImplementation(property.DeclaringType, property);
}
/// <summary>
/// Changes the given value to the given type.
/// </summary>
/// <param name="value"></param>
/// <param name="type"></param>
/// <returns></returns>
public static object ChangeType(object value, Type type)
{
if (type == null)
throw new ArgumentNullException("type");
// Handle null value
if (value == null)
{
if (type.CanBeNull())
return null;
throw new InvalidCastException(string.Format("Unable to convert NULL to type {0}", type.Name));
}
Type valueType = value.GetType();
if (valueType.IsAssignableTo(type))
return value;
try
{
// Handle enum
if (type.IsEnum)
{
if (valueType.IsIntegerNumeric())
return Enum.ToObject(type, value);
if (value is string)
return Enum.Parse(type, value as string, false);
}
return Convert.ChangeType(value, type, null);
}
catch (Exception e)
{
string valueString = valueType.ToString();
string message = string.Format("Failed to convert {0} to type {1} - {2}", valueString, type, e.Message);
throw new InvalidCastException(message, e);
}
}
} }
} }