diff --git a/ICD.Common.Utils/Attributes/RangeAttribute.cs b/ICD.Common.Utils/Attributes/RangeAttribute.cs
new file mode 100644
index 0000000..31907e0
--- /dev/null
+++ b/ICD.Common.Utils/Attributes/RangeAttribute.cs
@@ -0,0 +1,231 @@
+using System;
+
+namespace ICD.Common.Utils.Attributes
+{
+ ///
+ /// Indicates the valid ranges for a given value if that range is not equal to the range of the data type.
+ ///
+ [AttributeUsage(AttributeTargets.Property |
+ AttributeTargets.Field |
+ AttributeTargets.Parameter |
+ AttributeTargets.ReturnValue,
+ AllowMultiple = false,
+ Inherited = true)]
+ public class RangeAttribute : AbstractIcdAttribute
+ {
+ public object Min { get; private set; }
+ public object Max { get; private set; }
+
+ public RangeAttribute(ushort min, ushort max)
+ {
+ Min = min;
+ Max = max;
+ }
+
+ public RangeAttribute(short min, short max)
+ {
+ Min = min;
+ Max = max;
+ }
+
+ public RangeAttribute(uint min, uint max)
+ {
+ Min = min;
+ Max = max;
+ }
+
+ public RangeAttribute(int min, int max)
+ {
+ Min = min;
+ Max = max;
+ }
+
+ public RangeAttribute(ulong min, ulong max)
+ {
+ Min = min;
+ Max = max;
+ }
+
+ public RangeAttribute(long min, long max)
+ {
+ Min = min;
+ Max = max;
+ }
+
+ public RangeAttribute(float min, float max)
+ {
+ Min = min;
+ Max = max;
+ }
+
+ public RangeAttribute(double min, double max)
+ {
+ Min = min;
+ Max = max;
+ }
+
+ public RangeAttribute(byte min, byte max)
+ {
+ Min = min;
+ Max = max;
+ }
+
+ public RangeAttribute(sbyte min, sbyte max)
+ {
+ Min = min;
+ Max = max;
+ }
+
+ public RangeAttribute(decimal min, decimal max)
+ {
+ Min = min;
+ Max = max;
+ }
+
+ public bool IsInRange(object value)
+ {
+ if (value is ushort)
+ {
+ if (!(Min is ushort))
+ throw new ArgumentException("the type of value does not match the type of min / max");
+
+ var castMin = (ushort)Min;
+ var castMax = (ushort)Max;
+ var castVal = (ushort)value;
+ return (castVal >= castMin && castVal <= castMax);
+ }
+
+ if (value is short)
+ {
+ if (!(Min is short))
+ throw new ArgumentException("the type of value does not match the type of min / max");
+
+ var castMin = (short)Min;
+ var castMax = (short)Max;
+ var castVal = (short)value;
+ return (castVal >= castMin && castVal <= castMax);
+ }
+
+ if (value is uint)
+ {
+ if (!(Min is uint))
+ throw new ArgumentException("the type of value does not match the type of min / max");
+
+ var castMin = (uint)Min;
+ var castMax = (uint)Max;
+ var castVal = (uint)value;
+ return (castVal >= castMin && castVal <= castMax);
+ }
+
+ if (value is int)
+ {
+ if (!(Min is int))
+ throw new ArgumentException("the type of value does not match the type of min / max");
+
+ var castMin = (int)Min;
+ var castMax = (int)Max;
+ var castVal = (int)value;
+ return (castVal >= castMin && castVal <= castMax);
+ }
+
+ if (value is ulong)
+ {
+ if (!(Min is ulong))
+ throw new ArgumentException("the type of value does not match the type of min / max");
+
+ var castMin = (ulong)Min;
+ var castMax = (ulong)Max;
+ var castVal = (ulong)value;
+ return (castVal >= castMin && castVal <= castMax);
+ }
+
+ if (value is long)
+ {
+ if (!(Min is long))
+ throw new ArgumentException("the type of value does not match the type of min / max");
+
+ var castMin = (long)Min;
+ var castMax = (long)Max;
+ var castVal = (long)value;
+ return (castVal >= castMin && castVal <= castMax);
+ }
+
+ if (value is float)
+ {
+ if (!(Min is float))
+ throw new ArgumentException("the type of value does not match the type of min / max");
+
+ var castMin = (float)Min;
+ var castMax = (float)Max;
+ var castVal = (float)value;
+ return (castVal >= castMin && castVal <= castMax);
+ }
+
+ if (value is double)
+ {
+ if (!(Min is double))
+ throw new ArgumentException("the type of value does not match the type of min / max");
+
+ var castMin = (double)Min;
+ var castMax = (double)Max;
+ var castVal = (double)value;
+ return (castVal >= castMin && castVal <= castMax);
+ }
+
+ if (value is decimal)
+ {
+ if (!(Min is decimal))
+ throw new ArgumentException("the type of value does not match the type of min / max");
+
+ var castMin = (decimal)Min;
+ var castMax = (decimal)Max;
+ var castVal = (decimal)value;
+ return (castVal >= castMin && castVal <= castMax);
+ }
+
+ if (value is byte)
+ {
+ if (!(Min is byte))
+ throw new ArgumentException("the type of value does not match the type of min / max");
+
+ var castMin = (byte)Min;
+ var castMax = (byte)Max;
+ var castVal = (byte)value;
+ return (castVal >= castMin && castVal <= castMax);
+ }
+
+ if (value is sbyte)
+ {
+ if (!(Min is sbyte))
+ throw new ArgumentException("the type of value does not match the type of min / max");
+
+ var castMin = (sbyte)Min;
+ var castMax = (sbyte)Max;
+ var castVal = (sbyte)value;
+ return (castVal >= castMin && castVal <= castMax);
+ }
+
+ throw new ArgumentException("the type of value is not a numeric type.");
+ }
+
+ public ushort RemapRangeToUshort(double value)
+ {
+ return (ushort)MathUtils.MapRange((double)Min, (double)Max, ushort.MinValue, ushort.MaxValue, value);
+ }
+
+ public ushort RemapRangeToUshort(float value)
+ {
+ return (ushort)MathUtils.MapRange((float)Min, (float)Max, ushort.MinValue, ushort.MaxValue, value);
+ }
+
+ public ushort RemapRangeToUshort(int value)
+ {
+ return (ushort)MathUtils.MapRange((int)Min, (int)Max, ushort.MinValue, ushort.MaxValue, value);
+ }
+
+ public ushort RemapRangeToUshort(ushort value)
+ {
+ return MathUtils.MapRange((ushort)Min, (ushort)Max, ushort.MinValue, ushort.MaxValue, value);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj b/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj
index f9eddd5..90d90a8 100644
--- a/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj
+++ b/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj
@@ -75,6 +75,7 @@
+
diff --git a/ICD.Common.Utils/ReflectionUtils.cs b/ICD.Common.Utils/ReflectionUtils.cs
index 54584f6..a5b1ff6 100644
--- a/ICD.Common.Utils/ReflectionUtils.cs
+++ b/ICD.Common.Utils/ReflectionUtils.cs
@@ -4,6 +4,8 @@ using System.Linq;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
using ICD.Common.Utils.IO;
+using ICD.Common.Utils.Services;
+using ICD.Common.Utils.Services.Logging;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharp.Reflection;
@@ -216,7 +218,28 @@ namespace ICD.Common.Utils
if (parameters == null)
throw new ArgumentNullException("parameters");
- ConstructorInfo constructor = GetConstructor(type, parameters);
+ ConstructorInfo constructor = null;
+
+ try
+ {
+ constructor = GetConstructor(type, parameters);
+ }
+ catch (ArgumentException e)
+ {
+ var logger = ServiceProvider.GetService();
+
+ logger.AddEntry(eSeverity.Error, "Could not find constructor while attempting to create instance.");
+ logger.AddEntry(eSeverity.Error, "Attempted to create an instance of type {0}", type.ToString());
+ logger.AddEntry(eSeverity.Error, "With the following parameters:");
+ foreach (var param in parameters)
+ {
+ logger.AddEntry(eSeverity.Error, "Type:{0}, Value:{1}", param.GetType().ToString(), param.ToString());
+ }
+ logger.AddEntry(eSeverity.Error, "No valid constructor exists for this set of parameters.");
+ }
+
+ if (constructor == null)
+ return null;
try
{