diff --git a/DNX.Extensions.sln.DotSettings b/DNX.Extensions.sln.DotSettings
index 85a9b75..01a0a74 100644
--- a/DNX.Extensions.sln.DotSettings
+++ b/DNX.Extensions.sln.DotSettings
@@ -1,2 +1,3 @@
+ True
True
\ No newline at end of file
diff --git a/src/DNX.Extensions/Assemblies/AssemblyDetails.cs b/src/DNX.Extensions/Assemblies/AssemblyDetails.cs
new file mode 100644
index 0000000..6a86acb
--- /dev/null
+++ b/src/DNX.Extensions/Assemblies/AssemblyDetails.cs
@@ -0,0 +1,257 @@
+using System;
+using System.IO;
+using System.Reflection;
+using DNX.Extensions.Validation;
+
+namespace DNX.Extensions.Assemblies;
+
+///
+/// Implementation for obtaining Assembly Attributes
+///
+///
+public class AssemblyDetails : IAssemblyDetails
+{
+ #region Properties
+
+ ///
+ /// Internal Assembly field
+ ///
+ public Assembly Assembly { get; }
+
+ #endregion
+
+ #region Constructor(s)
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public AssemblyDetails()
+ : this(Assembly.GetCallingAssembly())
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The assembly.
+ public AssemblyDetails(Assembly assembly)
+ {
+ Guard.IsNotNull(() => assembly);
+
+ Assembly = assembly;
+ }
+
+ #endregion
+
+ #region Internal Methods
+
+ ///
+ /// Returns the value of attribute T or String.Empty if no value is available.
+ ///
+ /// The type of attribute to interrogate
+ /// The get value.
+ /// The result of the specified Func, executed on the found attribute, if any.
+ /// null if not matching attribute can be found
+ protected string GetValue(Func getValue)
+ where T : Attribute
+ {
+ var a = (T)Attribute.GetCustomAttribute(Assembly, typeof(T));
+
+ return a == null
+ ? null
+ : getValue(a);
+ }
+
+ #endregion
+
+ #region IAssemblyDetails Members
+
+ ///
+ /// Gets the AssemblyName
+ ///
+ /// The name of the assembly.
+ public AssemblyName AssemblyName
+ {
+ get { return Assembly.GetName(); }
+ }
+
+ ///
+ /// Gets the name of the assembly.
+ ///
+ /// The name.
+ public string Name
+ {
+ get { return AssemblyName.Name; }
+ }
+
+ ///
+ /// Gets the location of the assembly.
+ ///
+ /// The location.
+ public string Location
+ {
+ get { return Assembly.Location; }
+ }
+
+ ///
+ /// Gets the file name of the assembly.
+ ///
+ /// The name of the file.
+ public string FileName
+ {
+ get { return Path.GetFileName(Assembly.Location); }
+ }
+
+ ///
+ /// Gets the title attribute value.
+ ///
+ /// The title.
+ public string Title
+ {
+ get { return GetValue(a => a.Title); }
+ }
+
+ ///
+ /// Gets the product attribute value.
+ ///
+ /// The product.
+ public string Product
+ {
+ get { return GetValue(a => a.Product); }
+ }
+
+ ///
+ /// Gets the copyright attribute value.
+ ///
+ /// The copyright.
+ public string Copyright
+ {
+ get { return GetValue(a => a.Copyright); }
+ }
+
+ ///
+ /// Gets the company attribute value.
+ ///
+ /// The company.
+ public string Company
+ {
+ get { return GetValue(a => a.Company); }
+ }
+
+ ///
+ /// Gets the description attribute value.
+ ///
+ /// The description.
+ public string Description
+ {
+ get { return GetValue(a => a.Description); }
+ }
+
+ ///
+ /// Gets the trademark attribute value.
+ ///
+ /// The trademark.
+ public string Trademark
+ {
+ get { return GetValue(a => a.Trademark); }
+ }
+
+ ///
+ /// Gets the configuration attribute value.
+ ///
+ /// The configuration.
+ public string Configuration
+ {
+ get { return GetValue(a => a.Configuration); }
+ }
+
+ ///
+ /// Gets the assembly version.
+ ///
+ /// The version.
+ public Version Version
+ {
+ get { return AssemblyName.Version; }
+ }
+
+ ///
+ /// Gets or sets the simplified version.
+ ///
+ /// The simplified version.
+ public string SimplifiedVersion
+ {
+ get { return Version.Simplify(); }
+ }
+
+ ///
+ /// Gets the file version attribute value.
+ ///
+ /// The file version.
+ public string FileVersion
+ {
+ get { return GetValue(a => a.Version); }
+ }
+
+ ///
+ /// Gets the informational version attribute value.
+ ///
+ /// The informational version.
+ public string InformationalVersion
+ {
+ get { return GetValue(a => a.InformationalVersion); }
+ }
+
+ #endregion
+
+ #region Static Methods
+
+ ///
+ /// Creates an AssemblyDetails from the specified assembly.
+ ///
+ /// The assembly.
+ /// IAssemblyDetails.
+ public static IAssemblyDetails ForAssembly(Assembly assembly)
+ {
+ return new AssemblyDetails(assembly);
+ }
+
+ ///
+ /// Creates an AssemblyDetails for the calling assembly
+ ///
+ /// IAssemblyDetails.
+ public static IAssemblyDetails ForMe()
+ {
+ return ForAssembly(Assembly.GetCallingAssembly());
+ }
+
+ ///
+ /// Creates an AssemblyDetails for the entry point assembly.
+ ///
+ /// IAssemblyDetails.
+ public static IAssemblyDetails ForEntryPoint()
+ {
+ return ForAssembly(Assembly.GetEntryAssembly());
+ }
+
+ ///
+ /// Creates an AssemblyDetails fors the assembly containing the specified Type
+ ///
+ /// The type.
+ /// IAssemblyDetails.
+ public static IAssemblyDetails ForAssemblyContaining(Type type)
+ {
+ return ForAssembly(type.Assembly);
+ }
+
+ ///
+ /// Creates an AssemblyDetails fors the assembly containing the specified Type
+ ///
+ ///
+ /// IAssemblyDetails.
+ public static IAssemblyDetails ForAssemblyContaining()
+ {
+ return ForAssembly(typeof(T).Assembly);
+ }
+
+ #endregion
+}
diff --git a/src/DNX.Extensions/Assemblies/AssemblyExtensions.cs b/src/DNX.Extensions/Assemblies/AssemblyExtensions.cs
index 17c3c06..2325199 100644
--- a/src/DNX.Extensions/Assemblies/AssemblyExtensions.cs
+++ b/src/DNX.Extensions/Assemblies/AssemblyExtensions.cs
@@ -1,7 +1,10 @@
using System;
+using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Reflection;
using System.Resources;
+using DNX.Extensions.Reflection;
// ReSharper disable ConvertToUsingDeclaration
@@ -13,13 +16,71 @@ namespace DNX.Extensions.Assemblies;
public static class AssemblyExtensions
{
///
- /// Gets the embedded resource text.
+ /// Gets the assembly details.
///
/// The assembly.
- /// Name of the relative resource.
- /// The name space.
- ///
- ///
+ /// IAssemblyDetails.
+ public static IAssemblyDetails GetAssemblyDetails(this Assembly assembly)
+ {
+ return AssemblyDetails.ForAssembly(assembly);
+ }
+
+ ///
+ /// Find the types in the Assembly that implement the specified Type
+ ///
+ ///
+ /// The assembly.
+ /// IList<Type>.
+ public static IList FindTypesThatImplementType(this Assembly assembly)
+ {
+ var types = assembly.GetTypes()
+ .Where(t => t.IsA(typeof(T)))
+ .ToList();
+
+ return types;
+ }
+
+ ///
+ /// Find the concrete types in the Assembly that implement the specified Type
+ ///
+ /// The type to find classes that implement
+ /// The assembly to search
+ /// List of
+ public static IList FindConcreteTypesThatImplementType(this Assembly assembly)
+ {
+ var concreteClassTypes = FindTypesThatImplementType(assembly)
+ .Where((t => t.IsClass && !t.IsAbstract))
+ .ToList();
+
+ return concreteClassTypes;
+ }
+
+ ///
+ /// Create instances of concrete types in an assembly that implement the specified type
+ ///
+ ///
+ /// The assembly to search
+ /// List of instances of T>
+ public static IList CreateInstancesOfConcreteTypesThatImplementType(this Assembly assembly)
+ {
+ var types = assembly.FindConcreteTypesThatImplementType();
+
+ var instances = types
+ .Select(Activator.CreateInstance)
+ .Cast()
+ .ToList();
+
+ return instances;
+ }
+
+ ///
+ /// Gets the embedded resource text.
+ ///
+ /// The assembly.
+ /// Name of the relative resource.
+ /// The name space.
+ ///
+ ///
public static string GetEmbeddedResourceText(this Assembly assembly, string relativeResourceName, string nameSpace = null)
{
try
diff --git a/src/DNX.Extensions/Assemblies/IAssemblyDetails.cs b/src/DNX.Extensions/Assemblies/IAssemblyDetails.cs
new file mode 100644
index 0000000..6c7408f
--- /dev/null
+++ b/src/DNX.Extensions/Assemblies/IAssemblyDetails.cs
@@ -0,0 +1,100 @@
+using System;
+using System.Reflection;
+
+namespace DNX.Extensions.Assemblies;
+
+///
+/// Interface IAssemblyDetail
+///
+public interface IAssemblyDetails
+{
+ ///
+ /// Gets the AssemblyName
+ ///
+ /// The name of the assembly.
+ AssemblyName AssemblyName { get; }
+
+ ///
+ /// Gets the name of the assembly.
+ ///
+ /// The name.
+ string Name { get; }
+
+ ///
+ /// Gets the location of the assembly.
+ ///
+ /// The location.
+ string Location { get; }
+
+ ///
+ /// Gets the file name of the assembly.
+ ///
+ /// The name of the file.
+ string FileName { get; }
+
+ ///
+ /// Gets the title attribute value.
+ ///
+ /// The title.
+ string Title { get; }
+
+ ///
+ /// Gets the product attribute value.
+ ///
+ /// The product.
+ string Product { get; }
+
+ ///
+ /// Gets the copyright attribute value.
+ ///
+ /// The copyright.
+ string Copyright { get; }
+
+ ///
+ /// Gets the company attribute value.
+ ///
+ /// The company.
+ string Company { get; }
+
+ ///
+ /// Gets the description attribute value.
+ ///
+ /// The description.
+ string Description { get; }
+
+ ///
+ /// Gets the trademark attribute value.
+ ///
+ /// The trademark.
+ string Trademark { get; }
+
+ ///
+ /// Gets the configuration attribute value.
+ ///
+ /// The configuration.
+ string Configuration { get; }
+
+ ///
+ /// Gets the assembly version.
+ ///
+ /// The version.
+ Version Version { get; }
+
+ ///
+ /// Gets the simplified version.
+ ///
+ /// The simplified version.
+ string SimplifiedVersion { get; }
+
+ ///
+ /// Gets the file version attribute value.
+ ///
+ /// The file version.
+ string FileVersion { get; }
+
+ ///
+ /// Gets the informational version attribute value.
+ ///
+ /// The informational version.
+ string InformationalVersion { get; }
+}
diff --git a/src/DNX.Extensions/Assemblies/VersionExtensions.cs b/src/DNX.Extensions/Assemblies/VersionExtensions.cs
new file mode 100644
index 0000000..86a3468
--- /dev/null
+++ b/src/DNX.Extensions/Assemblies/VersionExtensions.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using DNX.Extensions.Validation;
+
+namespace DNX.Extensions.Assemblies;
+
+///
+/// Class VersionExtensions.
+///
+public static class VersionExtensions
+{
+ ///
+ /// Simplifies the Version to the specified minimum positions
+ ///
+ /// The version.
+ /// The minimum positions.
+ /// System.String.
+ public static string Simplify(this Version version, int minimumPositions = 1)
+ {
+ // TODO: Restore when available
+ //Guard.IsBetween(() => minimumPositions, 1, 4, IsBetweenBoundsType.IncludeLowerAndUpper);
+
+ if (version == null)
+ {
+ return null;
+ }
+
+ var parts = new List( version.ToString().Split('.'));
+
+ while (parts.Any() && parts.Last().Equals("0") && parts.Count > minimumPositions)
+ {
+ parts = parts.Take(parts.Count - 1).ToList();
+ }
+
+ var versionText = string.Join(".", parts);
+
+ return versionText;
+ }
+}
diff --git a/src/DNX.Extensions/Comparers/ComparerFunc.cs b/src/DNX.Extensions/Comparers/ComparerFunc.cs
new file mode 100644
index 0000000..745cec5
--- /dev/null
+++ b/src/DNX.Extensions/Comparers/ComparerFunc.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+
+namespace DNX.Extensions.Comparers;
+
+///
+/// Class ComparerFunc.
+///
+///
+///
+public class ComparerFunc : IComparer
+{
+ private readonly Func _func;
+
+ private ComparerFunc(Func func)
+ {
+ _func = func;
+ }
+
+ ///
+ /// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
+ ///
+ /// The first object to compare.
+ /// The second object to compare.
+ /// A signed integer that indicates the relative values of and , as shown in the following table.Value Meaning Less than zero is less than .Zero equals .Greater than zero is greater than .
+ public int Compare(T x, T y)
+ {
+ return _func(x, y);
+ }
+
+ ///
+ /// Creates a comparer for the specified type
+ ///
+ /// The function.
+ /// ActionComparer<T>.
+ public static ComparerFunc Create(Func func)
+ {
+ return new ComparerFunc(func);
+ }
+}
diff --git a/src/DNX.Extensions/Comparers/EqualityComparerFunc.cs b/src/DNX.Extensions/Comparers/EqualityComparerFunc.cs
new file mode 100644
index 0000000..8ad57c7
--- /dev/null
+++ b/src/DNX.Extensions/Comparers/EqualityComparerFunc.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+
+namespace DNX.Extensions.Comparers;
+
+///
+/// Class EqualityComparerFunc.
+///
+///
+///
+public class EqualityComparerFunc : IEqualityComparer
+{
+ private readonly Func _func;
+
+ private EqualityComparerFunc(Func func)
+ {
+ _func = func;
+ }
+
+ ///
+ /// Determines whether the specified objects are equal.
+ ///
+ /// The first object to compare.
+ /// The second object to compare.
+ /// true if the specified objects are equal; otherwise, false.
+ public bool Equals(T x, T y)
+ {
+ return _func(x, y);
+ }
+
+ ///
+ /// Returns a hash code for this instance.
+ ///
+ /// The for which a hash code is to be returned.
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
+ public int GetHashCode(T obj)
+ {
+ return 0;
+ }
+
+ ///
+ /// Creates a comparer for the specified type
+ ///
+ /// The function.
+ /// ActionEqualityComparer<T>.
+ public static EqualityComparerFunc Create(Func func)
+ {
+ return new EqualityComparerFunc(func);
+ }
+}
diff --git a/src/DNX.Extensions/Comparers/StringComparisonEqualityComparer.cs b/src/DNX.Extensions/Comparers/StringComparisonEqualityComparer.cs
index 194ad7a..0a2a7db 100644
--- a/src/DNX.Extensions/Comparers/StringComparisonEqualityComparer.cs
+++ b/src/DNX.Extensions/Comparers/StringComparisonEqualityComparer.cs
@@ -57,7 +57,7 @@ public bool Equals(string x, string y)
public int GetHashCode(string obj)
{
if (Equals(obj?.ToLowerInvariant(), obj?.ToUpperInvariant()))
- return obj?.ToLowerInvariant().GetHashCode() ?? default;
+ return obj?.ToLowerInvariant().GetHashCode() ?? 0;
return obj.GetHashCode();
}
diff --git a/src/DNX.Extensions/Conversion/ConvertExtensions.cs b/src/DNX.Extensions/Conversion/ConvertExtensions.cs
index 04f8112..d135bae 100644
--- a/src/DNX.Extensions/Conversion/ConvertExtensions.cs
+++ b/src/DNX.Extensions/Conversion/ConvertExtensions.cs
@@ -3,97 +3,44 @@
namespace DNX.Extensions.Conversion;
///
-/// Extensions to simplify type conversion
+/// Conversion Extensions.
///
public static class ConvertExtensions
{
///
- /// Converts to string, or default.
- ///
- /// The object.
- /// The default value.
- /// System.String.
- public static string ToStringOrDefault(this object obj, string defaultValue = "")
- {
- return obj?.ToString() ?? defaultValue;
- }
-
- ///
- /// Converts to boolean.
- ///
- /// The text.
- /// The default value.
- /// true/false if can be converted, defaultValue otherwise.
- public static bool ToBoolean(this string text, bool defaultValue = default)
- {
- return bool.TryParse(text, out var value)
- ? value
- : defaultValue;
- }
-
- ///
- /// Converts to int32.
- ///
- /// The text.
- /// The default value.
- /// System.Int32.
- public static int ToInt32(this string text, int defaultValue = default)
- {
- return int.TryParse(text, out var value)
- ? value
- : defaultValue;
- }
-
- ///
- /// Converts to enum.
+ /// Changes the value to the specified type
///
///
- /// The text.
- /// The default value.
+ /// The value.
/// T.
- public static T ToEnum(this string text, T defaultValue = default)
- where T : struct
+ public static T ChangeType(this object value)
{
- return Enum.TryParse(text, true, out T value)
- ? value
- : defaultValue;
+ return (T)ChangeType(value, typeof(T));
}
///
- /// Converts to guid.
+ /// Changes the value to the specified type
///
- /// The text.
- /// Guid.
- public static Guid ToGuid(this string text)
- {
- return text.ToGuid(Guid.Empty);
- }
-
- ///
- /// Converts to guid.
- ///
- /// The text.
- /// The default value.
- /// Guid.
- public static Guid ToGuid(this string text, Guid defaultValue)
+ /// The value.
+ /// The type.
+ /// object
+ public static object ChangeType(this object value, Type type)
{
- return Guid.TryParse(text, out var result)
- ? result
- : defaultValue;
+ return Convert.ChangeType(value, type);
}
///
- /// Converts to the specified type.
+ /// Changes the value to the specified type, with a default value if conversion fails
///
///
- /// The object.
+ /// The value.
/// The default value.
/// T.
- public static T To(this object obj, T defaultValue = default)
+ public static T ChangeType(this object value, T defaultValue)
{
try
{
- return (T)obj ?? defaultValue;
+ return ChangeType(value);
}
catch
{
diff --git a/src/DNX.Extensions/Conversion/ConvertExtensionsOLD.cs b/src/DNX.Extensions/Conversion/ConvertExtensionsOLD.cs
new file mode 100644
index 0000000..9a957d5
--- /dev/null
+++ b/src/DNX.Extensions/Conversion/ConvertExtensionsOLD.cs
@@ -0,0 +1,105 @@
+using System;
+
+namespace DNX.Extensions.Conversion;
+
+///
+/// Extensions to simplify type conversion
+///
+public static class ConvertExtensionsOLD
+{
+ // TODO: These move to specific code-generated classes
+
+ ///
+ /// Converts to string, or default.
+ ///
+ /// The object.
+ /// The default value.
+ /// System.String.
+ public static string ToStringOrDefault(this object obj, string defaultValue = "")
+ {
+ return obj?.ToString() ?? defaultValue;
+ }
+
+ ///
+ /// Converts to boolean.
+ ///
+ /// The text.
+ /// The default value.
+ /// true/false the value if it can be converted, defaultValue otherwise.
+ public static bool ToBoolean(this string text, bool defaultValue = false)
+ {
+ return bool.TryParse(text, out var value)
+ ? value
+ : defaultValue;
+ }
+
+ ///
+ /// Converts to int32.
+ ///
+ /// The text.
+ /// The default value.
+ /// System.Int32.
+ public static int ToInt32(this string text, int defaultValue = 0)
+ {
+ return int.TryParse(text, out var value)
+ ? value
+ : defaultValue;
+ }
+
+ ///
+ /// Converts to enum.
+ ///
+ ///
+ /// The text.
+ /// The default value.
+ /// T.
+ public static T ToEnum(this string text, T defaultValue = default)
+ where T : struct
+ {
+ return Enum.TryParse(text, true, out T value)
+ ? value
+ : defaultValue;
+ }
+
+ ///
+ /// Converts to guid.
+ ///
+ /// The text.
+ /// Guid.
+ public static Guid ToGuid(this string text)
+ {
+ return text.ToGuid(Guid.Empty);
+ }
+
+ ///
+ /// Converts to guid.
+ ///
+ /// The text.
+ /// The default value.
+ /// Guid.
+ public static Guid ToGuid(this string text, Guid defaultValue)
+ {
+ return Guid.TryParse(text, out var result)
+ ? result
+ : defaultValue;
+ }
+
+ ///
+ /// Converts to the specified type.
+ ///
+ ///
+ /// The object.
+ /// The default value.
+ /// T.
+ public static T To(this object obj, T defaultValue = default)
+ {
+ try
+ {
+ return (T)obj ?? defaultValue;
+ }
+ catch
+ {
+ return defaultValue;
+ }
+ }
+}
diff --git a/src/DNX.Extensions/DNX.Extensions.csproj b/src/DNX.Extensions/DNX.Extensions.csproj
index 244a8f3..1bb1ec5 100644
--- a/src/DNX.Extensions/DNX.Extensions.csproj
+++ b/src/DNX.Extensions/DNX.Extensions.csproj
@@ -38,4 +38,8 @@
+
+
+
+
diff --git a/src/DNX.Extensions/DateTimes/DateTimeExtensions.cs b/src/DNX.Extensions/DateTimes/DateTimeExtensions.cs
index 15370b8..7fda2cd 100644
--- a/src/DNX.Extensions/DateTimes/DateTimeExtensions.cs
+++ b/src/DNX.Extensions/DateTimes/DateTimeExtensions.cs
@@ -7,6 +7,85 @@ namespace DNX.Extensions.DateTimes;
///
public static class DateTimeExtensions
{
+ ///
+ /// Gets the unix epoch.
+ ///
+ /// The unix epoch.
+ public static DateTime UnixEpoch
+ {
+ get { return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); }
+ }
+
+ ///
+ /// Parses the date as UTC.
+ ///
+ /// The date string.
+ /// DateTime.
+ public static DateTime ParseDateAsUtc(this string dateString)
+ {
+ var dateTime = DateTime.Parse(dateString);
+
+ var dateTimeUtc = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc);
+
+ return dateTimeUtc;
+ }
+
+ ///
+ /// Parses the date as UTC.
+ ///
+ /// The date string.
+ /// The format provider.
+ /// DateTime.
+ public static DateTime ParseDateAsUtc(this string dateString, IFormatProvider formatProvider)
+ {
+ var dateTime = DateTime.Parse(dateString, formatProvider);
+
+ var dateTimeUtc = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc);
+
+ return dateTimeUtc;
+ }
+
+ ///
+ /// Parses the date as UTC.
+ ///
+ /// The date string.
+ /// The default date time.
+ /// DateTime.
+ public static DateTime ParseDateAsUtc(this string dateString, DateTime defaultDateTime)
+ {
+ try
+ {
+ var dateTime = ParseDateAsUtc(dateString);
+
+ return dateTime;
+ }
+ catch
+ {
+ return DateTime.SpecifyKind(defaultDateTime, DateTimeKind.Utc);
+ }
+ }
+
+ ///
+ /// Parses the date as UTC.
+ ///
+ /// The date string.
+ /// The format provider.
+ /// The default date time.
+ /// System.DateTime.
+ public static DateTime ParseDateAsUtc(this string dateString, IFormatProvider formatProvider, DateTime defaultDateTime)
+ {
+ try
+ {
+ var dateTime = ParseDateAsUtc(dateString, formatProvider);
+
+ return dateTime;
+ }
+ catch
+ {
+ return DateTime.SpecifyKind(defaultDateTime, DateTimeKind.Utc);
+ }
+ }
+
///
/// Sets the year.
///
diff --git a/src/DNX.Extensions/Defaults.cs b/src/DNX.Extensions/Defaults.cs
new file mode 100644
index 0000000..7285977
--- /dev/null
+++ b/src/DNX.Extensions/Defaults.cs
@@ -0,0 +1,29 @@
+using System.Reflection;
+
+namespace DNX.Extensions;
+
+///
+/// Default values
+///
+public class Defaults
+{
+ ///
+ /// The default property information binding flags for reading via reflection
+ ///
+ public const BindingFlags PropertyInfoReaderBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty;
+
+ ///
+ /// The default property information binding flags for writing via reflection
+ ///
+ public const BindingFlags PropertyInfoWriterBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty;
+
+ ///
+ /// The default field information binding flags for reading via reflection
+ ///
+ public const BindingFlags FieldInfoReaderBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetField;
+
+ ///
+ /// The default field information binding flags for writing via reflection
+ ///
+ public const BindingFlags FieldInfoWriterBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetField;
+}
diff --git a/src/DNX.Extensions/Enumerations/EnumerationExtensions.cs b/src/DNX.Extensions/Enumerations/EnumerationExtensions.cs
new file mode 100644
index 0000000..9a3f2ce
--- /dev/null
+++ b/src/DNX.Extensions/Enumerations/EnumerationExtensions.cs
@@ -0,0 +1,463 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using DNX.Extensions.Exceptions;
+using System.Linq;
+using DNX.Extensions.Linq;
+using DNX.Extensions.Reflection;
+using DNX.Extensions.Strings;
+
+namespace DNX.Extensions.Enumerations;
+
+///
+/// Enum Extensions
+///
+public static class EnumerationExtensions
+{
+ ///
+ /// Translate a given string to an enumeration value.
+ /// May throw a translation exception
+ ///
+ /// The enum type to translate to
+ /// The string representation of an enum value of T
+ /// The result
+ public static T ParseEnum(this string item)
+ where T : struct
+ {
+ return ParseEnum(item, false);
+ }
+
+ ///
+ /// Translate a given string to an enumeration value.
+ /// May throw a translation exception
+ ///
+ /// The enum type to translate to
+ /// The string representation of an enum value of T
+ /// if set to true ignore the case of item.
+ /// The result
+ ///
+ public static T ParseEnum(this string item, bool ignoreCase)
+ where T : struct
+ {
+ if (typeof(T).IsEnum == false)
+ {
+ throw new EnumTypeException(typeof(T));
+ }
+
+ return (T)Enum.Parse(typeof(T), item, ignoreCase);
+ }
+
+ ///
+ /// Attempt to safely translate a string to an enumeration value.
+ /// If translation is not possible return a default value
+ ///
+ /// The enum type to translate to
+ /// The string representation of an enum value of T
+ /// The default value to return if translation cannot complete
+ /// T.
+ ///
+ public static T ParseEnumOrDefault(this string item, T defaultValue)
+ where T : struct
+ {
+ return ParseEnumOrDefault(item, false, defaultValue);
+ }
+
+ ///
+ /// Attempt to safely translate a string to an enumeration value.
+ /// If translation is not possible return a default value
+ ///
+ /// The enum type to translate to
+ /// The string representation of an enum value of T
+ /// if set to true [ignore case].
+ /// The default value to return if translation cannot complete
+ /// T.
+ ///
+ public static T ParseEnumOrDefault(this string item, bool ignoreCase, T defaultValue)
+ where T : struct
+ {
+ if (typeof(T).IsEnum == false)
+ {
+ throw new EnumTypeException(typeof(T));
+ }
+
+ try
+ {
+ return (T)Enum.Parse(typeof(T), item, ignoreCase);
+ }
+ catch
+ {
+ return defaultValue;
+ }
+ }
+
+ ///
+ /// Gets the specified attributes from an enum value
+ ///
+ ///
+ /// The value.
+ /// IList<T>.
+ public static IList GetAttributes(this Enum value)
+ {
+ return value.GetAttributes(false);
+ }
+
+ ///
+ /// Gets the specified attributes from an enum value
+ ///
+ ///
+ /// The value.
+ /// if set to true [inherit].
+ /// IList<T>.
+ public static IList GetAttributes(this Enum value, bool inherit)
+ {
+ var type = value.GetType();
+
+ var memInfo = type.GetMember(value.ToString())
+ .SingleOrDefault();
+
+ var attributes = memInfo?.GetMemberAttributes(inherit);
+
+ return attributes;
+ }
+
+ ///
+ /// Gets the specified attribute from an enum value
+ ///
+ ///
+ /// The value.
+ /// T.
+ public static T GetAttribute(this Enum value)
+ {
+ return value.GetAttribute(false);
+ }
+
+ ///
+ /// Gets the specified attribute from an enum value
+ ///
+ ///
+ /// The value.
+ /// if set to true [inherit].
+ /// T.
+ public static T GetAttribute(this Enum value, bool inherit)
+ {
+ var attributes = value.GetAttributes(inherit);
+
+ return attributes.FirstOrDefault();
+ }
+
+ ///
+ /// Gets the description property from the Description attribute from an enum value
+ ///
+ /// The value.
+ /// System.String.
+ public static string GetDescription(this Enum value)
+ {
+ return value.GetDescription(false);
+ }
+
+ ///
+ /// Gets the description property from the Description attribute from an enum value
+ ///
+ /// The value.
+ /// if set to true [inherit].
+ /// System.String.
+ public static string GetDescription(this Enum value, bool inherit)
+ {
+ var descriptionAttributes = value.GetAttributes(inherit);
+
+ return descriptionAttributes.HasAny()
+ ? descriptionAttributes.First().Description
+ : null;
+ }
+
+ ///
+ /// Gets the description of an enum value via Attribute or Name
+ ///
+ /// The value.
+ /// System.String.
+ public static string GetDescriptionOrName(this Enum value)
+ {
+ return value.GetDescriptionOrName(false);
+ }
+ ///
+ ///
+ /// The Enumeration
+ /// Whether inherited classes are interrogated
+ /// A string representing the friendly name
+ public static string GetDescriptionOrName(this Enum value, bool inherit)
+ {
+ return value.GetDescription()
+ .CoalesceNullWith(value.ToString());
+ }
+
+ ///
+ /// Determines whether the specified enum value is a valid enum name.
+ ///
+ ///
+ /// The enum value.
+ /// true if the specified value is valid; otherwise, false.
+ public static bool IsValidEnum(this T value)
+ where T : struct
+ {
+ return Convert.ToString(value).IsValidEnum();
+ }
+
+ ///
+ /// Determines whether the specified enum value is a valid enum name.
+ ///
+ ///
+ /// The enum Name.
+ /// true if the specified value is valid; otherwise, false.
+ public static bool IsValidEnum(this string value)
+ where T : struct
+ {
+ return IsValidEnum(value, typeof(T), false);
+ }
+
+ ///
+ /// Determines whether the specified enum value is a valid enum name.
+ ///
+ ///
+ /// The value.
+ /// if set to true [ignore case].
+ /// true if [is valid enum] [the specified ignore case]; otherwise, false.
+ public static bool IsValidEnum(this string value, bool ignoreCase)
+ where T : struct
+ {
+ return IsValidEnum(value, typeof(T), ignoreCase);
+ }
+
+ ///
+ /// Determines whether the text is a valid enum value of the specified enum type
+ ///
+ /// The value.
+ /// The type.
+ /// if set to true [ignore case].
+ /// true if [is valid enum] [the specified type]; otherwise, false.
+ /// type
+ ///
+ public static bool IsValidEnum(this string value, Type type, bool ignoreCase)
+ {
+ if (type == null)
+ {
+ throw new ArgumentNullException(nameof(type));
+ }
+
+ if (!type.IsEnum)
+ {
+ throw new EnumTypeException(type);
+ }
+
+ var comparison = ignoreCase
+ ? StringComparison.CurrentCultureIgnoreCase
+ : StringComparison.CurrentCulture;
+
+ var names = Enum.GetNames(type)
+ .ToList();
+
+ return names.Any(n => n.Equals(value, comparison));
+ }
+
+ ///
+ /// Gets the max enum value.
+ ///
+ ///
+ /// T.
+ ///
+ public static T GetMaxValue()
+ where T : struct
+ {
+ if (!typeof(T).IsEnum)
+ {
+ throw new EnumTypeException(typeof(T));
+ }
+
+ return Enum.GetValues(typeof(T))
+ .Cast()
+ .Max();
+ }
+
+ ///
+ /// Gets the min enum value.
+ ///
+ ///
+ /// T.
+ ///
+ public static T GetMinValue()
+ where T : struct
+ {
+ if (!typeof(T).IsEnum)
+ {
+ throw new EnumTypeException(typeof(T));
+ }
+
+ return Enum.GetValues(typeof(T))
+ .Cast()
+ .Min();
+ }
+
+ ///
+ /// Determines whether [is value one of] [the specified args].
+ ///
+ ///
+ /// The value.
+ /// The allowed.
+ /// true if [is value one of] [the specified args]; otherwise, false.
+ public static bool IsValueOneOf(this T value, params T[] allowed)
+ where T : struct
+ {
+ return value.IsValueOneOf(allowed.ToList());
+ }
+
+ ///
+ /// Determines whether [is value one of] [the specified args].
+ ///
+ ///
+ /// The value.
+ /// The allowed.
+ /// true if [is value one of] [the specified args]; otherwise, false.
+ ///
+ public static bool IsValueOneOf(this T value, IList allowed)
+ where T : struct
+ {
+ if (!typeof(T).IsEnum)
+ {
+ throw new EnumTypeException(typeof(T));
+ }
+
+ return allowed.Contains(value);
+ }
+
+ ///
+ /// Sets the flag.
+ ///
+ ///
+ /// The value.
+ /// The flag.
+ /// if set to true [set].
+ /// T.
+ public static T ManipulateFlag(this Enum value, T flag, bool set)
+ {
+ var underlyingType = Enum.GetUnderlyingType(value.GetType());
+
+ // note: AsInt mean: math integer vs enum (not the c# int type)
+ dynamic valueAsInt = Convert.ChangeType(value, underlyingType);
+ dynamic flagAsInt = Convert.ChangeType(flag, underlyingType);
+
+ if (set)
+ {
+ valueAsInt |= flagAsInt;
+ }
+ else
+ {
+ valueAsInt &= ~flagAsInt;
+ }
+ return (T)valueAsInt;
+ }
+
+ ///
+ /// Sets the flag.
+ ///
+ ///
+ /// The value.
+ /// The flag.
+ /// T.
+ public static T SetFlag(this Enum value, T flag)
+ {
+ return ManipulateFlag(value, flag, true);
+ }
+
+ ///
+ /// Unsets the flag.
+ ///
+ ///
+ /// The value.
+ /// The flag.
+ /// T.
+ public static T UnsetFlag(this Enum value, T flag)
+ {
+ return ManipulateFlag(value, flag, false);
+ }
+
+ ///
+ /// Gets the set values list.
+ ///
+ ///
+ /// The enum value.
+ /// List<T>.
+ ///
+ public static List GetSetValuesList(this Enum enumValue)
+ where T : struct
+ {
+ if (!typeof(T).IsEnum)
+ {
+ throw new EnumTypeException(typeof(T));
+ }
+
+ var list = new List();
+
+ foreach (var name in Enum.GetNames(typeof(T)))
+ {
+ var nameValue = (Enum)Enum.Parse(typeof(T), name);
+
+ if ((enumValue.HasFlag(nameValue)))
+ {
+ var actualValue = (T)Enum.Parse(typeof(T), name);
+
+ list.Add(actualValue);
+ }
+ }
+
+ return list;
+ }
+
+ ///
+ /// Converts the entire enum to a dictionary with Name as the key
+ ///
+ ///
+ /// IDictionary<System.String, T>.
+ ///
+ public static IDictionary ToDictionaryByName()
+ where T : struct
+ {
+ if (!typeof(T).IsEnum)
+ {
+ throw new EnumTypeException(typeof(T));
+ }
+
+ var dictionary = Enum.GetValues(typeof(T))
+ .Cast()
+ .Distinct()
+ .ToDictionary(
+ t => t.ToString(),
+ t => t
+ );
+
+ return dictionary;
+ }
+
+ ///
+ /// Converts the entire enum to a dictionary with Value as the key
+ ///
+ ///
+ /// IDictionary<T, System.String>.
+ ///
+ public static IDictionary ToDictionaryByValue()
+ where T : struct
+ {
+ if (!typeof(T).IsEnum)
+ {
+ throw new EnumTypeException(typeof(T));
+ }
+
+ var dictionary = Enum.GetValues(typeof(T))
+ .Cast()
+ .Distinct()
+ .ToDictionary(
+ t => t,
+ t => t.ToString()
+ );
+
+ return dictionary;
+ }
+}
diff --git a/src/DNX.Extensions/Enums/EnumExtensions.cs b/src/DNX.Extensions/Enums/EnumExtensions.cs
deleted file mode 100644
index 149107d..0000000
--- a/src/DNX.Extensions/Enums/EnumExtensions.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-using System;
-using System.ComponentModel;
-
-namespace DNX.Extensions.Enums;
-
-///
-/// Enum Extensions
-///
-public static class EnumExtensions
-{
- ///
- /// Gets the attribute.
- ///
- ///
- /// The en.
- ///
- public static T GetAttribute(this Enum en)
- {
- var type = en.GetType();
-
- var memInfo = type.GetMember(en.ToString());
-
- if (memInfo.Length > 0)
- {
- var attrs = memInfo[0].GetCustomAttributes(typeof(T), false);
-
- if (attrs.Length > 0)
- {
- return (T)attrs[0];
- }
- }
-
- return default;
- }
-
- ///
- /// Retrieve the description on the enum, e.g.
- /// [Description("Bright Pink")]
- /// BrightPink = 2,
- /// Then when you pass in the enum, it will retrieve the description
- ///
- /// The Enumeration
- /// A string representing the friendly name
- public static string GetDescription(this Enum en)
- {
- var attr = en.GetAttribute();
-
- return attr == null
- ? en.ToString()
- : attr.Description;
- }
-}
diff --git a/src/DNX.Extensions/Exceptions/ConversionException.cs b/src/DNX.Extensions/Exceptions/ConversionException.cs
new file mode 100644
index 0000000..22653c8
--- /dev/null
+++ b/src/DNX.Extensions/Exceptions/ConversionException.cs
@@ -0,0 +1,46 @@
+using System;
+
+namespace DNX.Extensions.Exceptions;
+
+///
+/// Conversion Exception.
+///
+///
+/// Thrown when a conversion to a specified type fails
+public class ConversionException : Exception
+{
+ ///
+ /// Gets the value.
+ ///
+ /// The value.
+ public string Value { get; private set; }
+
+ ///
+ /// Gets the type of the convert.
+ ///
+ /// The type of the convert.
+ public Type ConvertType { get; private set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The value.
+ /// The message.
+ public ConversionException(string value, string message)
+ : this(value, message, null)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The value.
+ /// The message.
+ /// The type.
+ public ConversionException(string value, string message, Type type)
+ : base(message)
+ {
+ Value = value;
+ ConvertType = type;
+ }
+}
diff --git a/src/DNX.Extensions/Exceptions/EnumTypeException.cs b/src/DNX.Extensions/Exceptions/EnumTypeException.cs
new file mode 100644
index 0000000..ee3d18d
--- /dev/null
+++ b/src/DNX.Extensions/Exceptions/EnumTypeException.cs
@@ -0,0 +1,42 @@
+using System;
+
+namespace DNX.Extensions.Exceptions;
+
+///
+/// EnumTypeException.
+///
+///
+public class EnumTypeException : Exception
+{
+ ///
+ /// The message template
+ ///
+ private const string MessageTemplate = "{0} is not an enumeration type";
+
+ ///
+ /// The type the exception was thrown for
+ ///
+ /// The type.
+ public Type Type { get; private set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The type.
+ /// Uses the default message template
+ public EnumTypeException(Type type)
+ : this(type, MessageTemplate)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The type.
+ /// The message template.
+ public EnumTypeException(Type type, string messageTemplate)
+ : base(string.Format(messageTemplate, type.Name))
+ {
+ Type = type;
+ }
+}
diff --git a/src/DNX.Extensions/Exceptions/EnumValueException.cs b/src/DNX.Extensions/Exceptions/EnumValueException.cs
new file mode 100644
index 0000000..604c327
--- /dev/null
+++ b/src/DNX.Extensions/Exceptions/EnumValueException.cs
@@ -0,0 +1,48 @@
+using System;
+
+namespace DNX.Extensions.Exceptions;
+
+///
+/// Class EnumValueException.
+///
+///
+public class EnumValueException : Exception
+{
+ ///
+ /// The message template
+ ///
+ private const string MessageTemplate = "{0} is not a valid {1} value";
+
+ ///
+ /// Gets the type.
+ ///
+ /// The type.
+ public Type Type { get; private set; }
+
+ ///
+ /// Gets the value.
+ ///
+ /// The value.
+ public T Value { get; private set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The value.
+ public EnumValueException(T value)
+ : this(value, MessageTemplate)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The value.
+ /// The message template.
+ public EnumValueException(T value, string messageTemplate)
+ : base(string.Format(messageTemplate, value, typeof(T).Name))
+ {
+ Type = typeof(T);
+ Value = value;
+ }
+}
diff --git a/src/DNX.Extensions/Exceptions/ExceptionExtensions.cs b/src/DNX.Extensions/Exceptions/ExceptionExtensions.cs
new file mode 100644
index 0000000..7cc1f38
--- /dev/null
+++ b/src/DNX.Extensions/Exceptions/ExceptionExtensions.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+
+namespace DNX.Extensions.Exceptions;
+
+///
+/// Exception Extensions.
+///
+public static class ExceptionExtensions
+{
+ ///
+ /// Gets the list of messages from an Exception and inner exceptions
+ ///
+ /// The ex.
+ /// IList<System.String>.
+ /// Also available as an extension method
+ public static IList GetMessageList(this Exception ex)
+ {
+ var list = new List();
+
+ while (ex != null)
+ {
+ list.Add(ex.Message);
+
+ ex = ex.InnerException;
+ }
+
+ return list;
+ }
+
+ ///
+ /// Gets the list of messages from an Exception and inner exceptions
+ ///
+ /// The ex.
+ /// IList<System.String>.
+ /// Also available as an extension method
+ public static IList GetExceptionList(this Exception ex)
+ {
+ var list = new List();
+
+ while (ex != null)
+ {
+ list.Add(ex);
+
+ ex = ex.InnerException;
+ }
+
+ return list;
+ }
+}
diff --git a/src/DNX.Extensions/Exceptions/ParameterException.cs b/src/DNX.Extensions/Exceptions/ParameterException.cs
new file mode 100644
index 0000000..9858839
--- /dev/null
+++ b/src/DNX.Extensions/Exceptions/ParameterException.cs
@@ -0,0 +1,72 @@
+using System;
+
+namespace DNX.Extensions.Exceptions;
+
+///
+/// An exception for idenifying issues with expected parameters
+///
+///
+public class ParameterException : Exception
+{
+ ///
+ /// The Parameter Name
+ ///
+ /// The name of the parameter.
+ public string ParamName { get; private set; }
+
+ ///
+ /// The value specified for the Parameter
+ ///
+ /// The parameter value.
+ public object ParamValue { get; private set; }
+
+ ///
+ /// Create a ParameterException with a parameter name and a message
+ ///
+ /// Name of the parameter.
+ /// The message.
+ public ParameterException(string paramName, string message)
+ : base(message)
+ {
+ ParamName = paramName;
+ }
+
+ ///
+ /// Create a ParameterException with a parameter name and value, and a message
+ ///
+ /// Name of the parameter.
+ /// The parameter value.
+ /// The message.
+ public ParameterException(string paramName, object paramValue, string message)
+ : base(message)
+ {
+ ParamName = paramName;
+ ParamValue = paramValue;
+ }
+
+ ///
+ /// Create a ParameterException with a parameter name, message and inner Exception
+ ///
+ /// Name of the parameter.
+ /// The message.
+ /// The inner exception.
+ public ParameterException(string paramName, string message, Exception innerException)
+ : base(message, innerException)
+ {
+ ParamName = paramName;
+ }
+
+ ///
+ /// Create a ParameterException with a parameter name and value, message and inner Exception
+ ///
+ /// Name of the parameter.
+ /// The parameter value.
+ /// The message.
+ /// The inner exception.
+ public ParameterException(string paramName, object paramValue, string message, Exception innerException)
+ : base(message, innerException)
+ {
+ ParamName = paramName;
+ ParamValue = paramValue;
+ }
+}
diff --git a/src/DNX.Extensions/Exceptions/ParameterInvalidException.cs b/src/DNX.Extensions/Exceptions/ParameterInvalidException.cs
new file mode 100644
index 0000000..d6ab88e
--- /dev/null
+++ b/src/DNX.Extensions/Exceptions/ParameterInvalidException.cs
@@ -0,0 +1,54 @@
+using System;
+
+namespace DNX.Extensions.Exceptions;
+
+///
+/// An exception for idenifying an invalid value issue with expected parameters
+///
+///
+public class ParameterInvalidException : ParameterException
+{
+ ///
+ /// Create a ParameterInvalidException with a parameter name and a message
+ ///
+ /// Name of the parameter.
+ /// The message.
+ public ParameterInvalidException(string paramName, string message)
+ : base(paramName, message)
+ {
+ }
+
+ ///
+ /// Create a ParameterInvalidException with a parameter name and value, and a message
+ ///
+ /// Name of the parameter.
+ /// The parameter value.
+ /// The message.
+ public ParameterInvalidException(string paramName, object paramValue, string message)
+ : base(paramName, paramValue, message)
+ {
+ }
+
+ ///
+ /// Create a ParameterInvalidException with a parameter name, message and inner Exception
+ ///
+ /// Name of the parameter.
+ /// The message.
+ /// The inner exception.
+ public ParameterInvalidException(string paramName, string message, Exception innerException)
+ : base(paramName, message, innerException)
+ {
+ }
+
+ ///
+ /// Create a ParameterInvalidException with a parameter name and value, message and inner Exception
+ ///
+ /// Name of the parameter.
+ /// The parameter value.
+ /// The message.
+ /// The inner exception.
+ public ParameterInvalidException(string paramName, object paramValue, string message, Exception innerException)
+ : base(paramName, paramValue, message, innerException)
+ {
+ }
+}
diff --git a/src/DNX.Extensions/Exceptions/ReadOnlyListException.cs b/src/DNX.Extensions/Exceptions/ReadOnlyListException.cs
new file mode 100644
index 0000000..113afee
--- /dev/null
+++ b/src/DNX.Extensions/Exceptions/ReadOnlyListException.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+
+namespace DNX.Extensions.Exceptions;
+
+///
+/// Class ReadOnlyListException.
+///
+///
+///
+public class ReadOnlyListException : Exception
+{
+ ///
+ /// Gets the list.
+ ///
+ /// The list.
+ public IList List { get; private set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The list.
+ public ReadOnlyListException(IList list)
+ {
+ List = list;
+ }
+}
diff --git a/src/DNX.Extensions/Interfaces/IConverter.cs b/src/DNX.Extensions/Interfaces/IConverter.cs
new file mode 100644
index 0000000..154c7bc
--- /dev/null
+++ b/src/DNX.Extensions/Interfaces/IConverter.cs
@@ -0,0 +1,16 @@
+namespace DNX.Extensions.Interfaces;
+
+///
+/// Converter Interface for transposing objects between 2 types
+///
+/// The type of the t1.
+/// The type of the t2.
+public interface IConverter
+{
+ ///
+ /// Converts the specified source.
+ ///
+ /// The source.
+ /// T2.
+ T2 Convert(T1 source);
+}
diff --git a/src/DNX.Extensions/Interfaces/IExtractable.cs b/src/DNX.Extensions/Interfaces/IExtractable.cs
new file mode 100644
index 0000000..f52dc4d
--- /dev/null
+++ b/src/DNX.Extensions/Interfaces/IExtractable.cs
@@ -0,0 +1,14 @@
+namespace DNX.Extensions.Interfaces;
+
+///
+/// Extractable Interface for populating another instance from this one
+///
+/// The type of the t1.
+public interface IExtractable
+{
+ ///
+ /// Extracts this object into another
+ ///
+ /// The target.
+ void ExtractInto(T1 target);
+}
diff --git a/src/DNX.Extensions/Interfaces/IPopulatable.cs b/src/DNX.Extensions/Interfaces/IPopulatable.cs
new file mode 100644
index 0000000..8c847d8
--- /dev/null
+++ b/src/DNX.Extensions/Interfaces/IPopulatable.cs
@@ -0,0 +1,14 @@
+namespace DNX.Extensions.Interfaces;
+
+///
+/// Populatable Interface for populating this object from another
+///
+/// The type of the t1.
+public interface IPopulatable
+{
+ ///
+ /// Populates from an instance of T1
+ ///
+ /// The source.
+ void PopulateFrom(T1 source);
+}
diff --git a/src/DNX.Extensions/Linq/DictionaryExtensions.cs b/src/DNX.Extensions/Linq/DictionaryExtensions.cs
new file mode 100644
index 0000000..fc97595
--- /dev/null
+++ b/src/DNX.Extensions/Linq/DictionaryExtensions.cs
@@ -0,0 +1,234 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Dynamic;
+using System.Linq;
+using DNX.Extensions.Exceptions;
+using DNX.Extensions.Validation;
+
+// ReSharper disable InconsistentNaming
+
+namespace DNX.Extensions.Linq;
+
+///
+/// Dictionary Extensions.
+///
+public static class DictionaryExtensions
+{
+ ///
+ /// Sets the value.
+ ///
+ /// The type of the tk.
+ /// The type of the tv.
+ /// The dictionary.
+ /// Name of the key.
+ /// The value.
+ /// dictionary or keyName
+ public static void SetValue(this IDictionary dictionary, TK keyName, TV value)
+ {
+ Guard.IsNotNull(() => dictionary);
+
+ if (keyName == null)
+ {
+ throw new ArgumentNullException(nameof(keyName));
+ }
+
+ if (dictionary.ContainsKey(keyName))
+ {
+ dictionary[keyName] = value;
+ }
+ else
+ {
+ dictionary.Add(keyName, value);
+ }
+ }
+
+ ///
+ /// Gets the value.
+ ///
+ /// The type of the tk.
+ /// The type of the tv.
+ /// The dictionary.
+ /// Name of the key.
+ /// The default value.
+ /// TV.
+ /// dictionary or keyName
+ public static TV GetValue(this IDictionary dictionary, TK keyName, TV defaultValue = default(TV))
+ {
+ Guard.IsNotNull(() => dictionary);
+
+ if (keyName == null)
+ {
+ throw new ArgumentNullException(nameof(keyName));
+ }
+
+ return dictionary.TryGetValue(keyName, out var value)
+ ? value
+ : defaultValue;
+ }
+
+ ///
+ /// Renames the key.
+ ///
+ ///
+ /// The dictionary.
+ /// Name of from key.
+ /// Name of to key.
+ /// fromKeyName or toKeyName
+ public static void RenameKey(this IDictionary dictionary, string fromKeyName, string toKeyName)
+ {
+ if (fromKeyName == null)
+ {
+ throw new ArgumentNullException(nameof(fromKeyName));
+ }
+ if (toKeyName == null)
+ {
+ throw new ArgumentNullException(nameof(toKeyName));
+ }
+
+ if (dictionary == null || !dictionary.ContainsKey(fromKeyName) || dictionary.ContainsKey(toKeyName))
+ {
+ return;
+ }
+
+ var old = dictionary[fromKeyName];
+ dictionary.Remove(fromKeyName);
+ dictionary.SetValue(toKeyName, old);
+ }
+
+ ///
+ /// Merges this dictionary with another one
+ ///
+ /// The type of the tk.
+ /// The type of the tv.
+ /// The dictionary.
+ /// The other.
+ /// The merge technique.
+ /// Dictionary<TK, TV>.
+ /// Source and target dictionaries are left untouched
+ public static IDictionary MergeWith(this IDictionary dict, IDictionary other, MergeTechnique mergeTechnique = MergeTechnique.Unique)
+ {
+ var result = Merge(mergeTechnique, dict, other);
+
+ return result;
+ }
+
+ ///
+ /// Merges dictionaries
+ ///
+ /// The type of the tk.
+ /// The type of the tv.
+ /// The merge technique.
+ /// The dictionaries.
+ /// Dictionary<TK, TV>.
+ /// Invalid or unsupported Merge Technique - mergeTechnique
+ public static IDictionary Merge(MergeTechnique mergeTechnique, params IDictionary[] dictionaries)
+ {
+ return mergeTechnique switch
+ {
+ MergeTechnique.Unique => MergeUnique(dictionaries),
+ MergeTechnique.TakeFirst => MergeFirst(dictionaries),
+ MergeTechnique.TakeLast => MergeLast(dictionaries),
+ _ => throw new EnumValueException(mergeTechnique)
+ };
+ }
+
+ ///
+ /// Merges dictionaries assuming all keys are unique
+ ///
+ /// The type of the tk.
+ /// The type of the tv.
+ /// The dictionaries.
+ /// Dictionary<TK, TV>.
+ public static IDictionary MergeUnique(params IDictionary[] dictionaries)
+ {
+ var dict = dictionaries.SelectMany(d => d)
+ .ToDictionary(pair => pair.Key, pair => pair.Value);
+
+ return dict;
+ }
+
+ ///
+ /// Merges dictionaries using the first found key value
+ ///
+ /// The type of the tk.
+ /// The type of the tv.
+ /// The dictionaries.
+ /// Dictionary<TK, TV>.
+ public static IDictionary MergeFirst(params IDictionary[] dictionaries)
+ {
+ var result = dictionaries.SelectMany(dict => dict)
+ .ToLookup(pair => pair.Key, pair => pair.Value)
+ .ToDictionary(group => group.Key, group => group.First());
+
+ return result;
+ }
+
+ ///
+ /// Merges dictionaries using the last found key value
+ ///
+ /// The type of the tk.
+ /// The type of the tv.
+ /// The dictionaries.
+ /// Dictionary<TK, TV>.
+ public static IDictionary MergeLast(params IDictionary[] dictionaries)
+ {
+ var result = dictionaries.SelectMany(dict => dict)
+ .ToLookup(pair => pair.Key, pair => pair.Value)
+ .ToDictionary(group => group.Key, group => group.Last());
+
+ return result;
+ }
+
+ ///
+ /// Extension method that turns a dictionary of string and object to an ExpandoObject
+ ///
+ public static ExpandoObject ToExpando(this IDictionary dictionary)
+ {
+ // TODO: Should really use AsDictionary
+
+ var expando = new ExpandoObject();
+ IDictionary expandoDict = expando;
+
+ // go through the items in the dictionary and copy over the key value pairs)
+ foreach (var kvp in dictionary)
+ {
+ switch (kvp.Value)
+ {
+ // if the value can also be turned into an ExpandoObject, then do it!
+ case IDictionary valueDictionary:
+ {
+ var expandoValue = valueDictionary.ToExpando();
+ expandoDict.Add(kvp.Key, expandoValue);
+ break;
+ }
+ case ICollection valueCollection:
+ {
+ // iterate through the collection and convert any strin-object dictionaries
+ // along the way into expando objects
+ var itemList = new List