Null Guard for Nested Objects With Hierarchy Path Recognition in C# - c#

I'm trying to create a nested Guard method (or find an existing Guard library) that would throw an exception if any object in a nested hierarchy is NULL and include the name of the object hierarchy path up to and including NULL. I also want to avoid fluent API syntax of checking each object. Please assume example below.
Assume the following hierarchy:
Country.State.City.Person
Example of usage I'm trying to achieve:
Guard.ThrowIfNull(Country.State.City.Person);
or
Guard.ThrowIfNull(() => Country.State.City.Person);
EXPECTED RESULT:
if Person is NULL, then throw ArgumentNullException("Country.State.City.Person")
if City is NULL, then throw ArgumentNullException("Country.State.City")
if State is NULL, then throw ArgumentNullException("Country.State")
if Country is NULL, then throw ArgumentNullException("Country")

At minimum, I believe you'll need to pass an instance to the Guard.ThrowIfNull function in addition to the path you want to check.
I wrote a proof of concept below that exhibits the behavior you describe. It does not handle collections, however. (In the case that State is a collection, this code will fail for "Country.State.City".)
Usage:
Guard.ThrowIfNull(country, "Country.State.City.Person");
// Or
Guard.ThrowIfNull(country, x => x.State.City.Person);
Code:
public static class Guard
{
/// <summary>
/// Throws an ArgumentNullException if any portion of a given property path is null.
/// </summary>
/// <typeparam name="T">The type to check.</typeparam>
/// <param name="instanceToCheck">The instance to check</param>
/// <param name="pathToCheck">The full path of the property to check. The path should include the name of the instance type.</param>
public static void ThrowIfNull<T>(T instanceToCheck, string pathToCheck)
{
var propsToCheck = pathToCheck?.Split('.');
if (propsToCheck?.Any() != true)
{
throw new ArgumentNullException(nameof(pathToCheck));
}
if (typeof(T).Name != propsToCheck.First())
{
throw new ArgumentException($"The type of {nameof(instanceToCheck)} does not match the given {nameof(pathToCheck)}.");
}
if (instanceToCheck == null)
{
throw new ArgumentNullException($"{pathToCheck.First()}");
}
object currentObj = instanceToCheck;
for (var i = 1; i < propsToCheck.Length; i++)
{
var prop = currentObj.GetType().GetProperties().FirstOrDefault(x => x.Name == propsToCheck[i]);
if (prop == null)
{
throw new ArgumentException($"The path, '{string.Join(".", propsToCheck.Take(i + 1))}' could not be found.");
}
currentObj = prop.GetValue(currentObj);
if (currentObj == null)
{
throw new ArgumentNullException($"{string.Join(".", propsToCheck.Take(i + 1))}");
}
}
}
/// <summary>
/// Throws an ArgumentNullException if any portion of a given property path is null.
/// </summary>
/// <typeparam name="T">The type to check.</typeparam>
/// <param name="instanceToCheck">The instance to check</param>
/// <param name="pathToCheck">The full path of the property to check.</param>
public static void ThrowIfNull<T, TProp>(T instanceToCheck, Expression<Func<T, TProp>> pathToCheck)
{
ThrowIfNull(instanceToCheck, (typeof(T).Name + pathToCheck.ToString().Substring(pathToCheck.ToString().IndexOf("."))));
}
}

Related

Compare and check if multiple variables, both reference types and value types, in object has changed in C#

In a system we are dependent on a third party service and once every minute we download data from them and update our data. It is related to E-signing so it is a lot of fields to update. Right now we are getting all the information and then we do an update on our side even if nothing has changed.
My thought was to do a deep copy using any of the methods shown below and then compare the values. However since there are so many variables I wonder if there is someway I can compare all values and see if they are equal and not have to write code to check each variable? An agreement as shown below have both value and reference types.
public class Agreement
{
//Properties here, both value and reference types
public bool HasChanged(Agreement oldagreement)
{
//Code here
}
}
Method example:
var oldagreement = agreement.Clone();
var document = client.GetThirdPartyAgreement(agreement.AgreementDocumentId);
UpdateDocument(agreement, document);
if(agreement.HasChanged(oldagreement)
{
agreementRepository.Update(agreement);
}
Deep copy extension methods:
/// <summary>
/// Perform a deep Copy of the object, using Json as a serialisation method. NOTE: Private members are not cloned using this method.
/// </summary>
/// <typeparam name="T">The type of object being copied.</typeparam>
/// <param name="source">The object instance to copy.</param>
/// <returns>The copied object.</returns>
public static T CloneJson<T>(this T source)
{
// Don't serialize a null object, simply return the default for that object
if (Object.ReferenceEquals(source, null))
{
return default(T);
}
// initialize inner objects individually
// for example in default constructor some list property initialized with some values,
// but in 'source' these items are cleaned -
// without ObjectCreationHandling.Replace default constructor values will be added to result
var deserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);
}
/// <summary>
/// Perform a deep Copy of the object.
/// </summary>
/// <typeparam name="T">The type of object being copied.</typeparam>
/// <param name="source">The object instance to copy.</param>
/// <returns>The copied object.</returns>
public static T Clone<T>(this T source)
{
if (!typeof(T).IsSerializable)
{
throw new ArgumentException("The type must be serializable.", "source");
}
// Don't serialize a null object, simply return the default for that object
if (Object.ReferenceEquals(source, null))
{
return default(T);
}
IFormatter formatter = new BinaryFormatter();
Stream stream = new MemoryStream();
using (stream)
{
formatter.Serialize(stream, source);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}
I got it to work using the tip from #LasseV.Karlsen. One problem I had was DateTimes however. When I compared the DateTime object in C# they were equal but when the metod Newtonsoft.Json.JsonConvert.SerializeObject() was called they generated a different time string. These were the strings generated 2016-10-21T10:42:09+02:00 and 2016-10-21T10:42:09.
I solved this by extending Newtonsoft.Json.Converters.IsoDateTimeConverter like the code below. Afterwards all DateTime objects had the same format.
public class CustomDateTimeConverter : IsoDateTimeConverter
{
public CustomDateTimeConverter()
{
base.DateTimeFormat = "yyyy-MM-ddTHH:mm:sszzz";
}
}
Working method example:
//CloneJson is the extension method from above - Deep copy
var oldAgreement = agreement.CloneJson();
var document = client.GetThirdPartyAgreement(agreement.AgreementDocumentId);
UpdateDocument(agreement, document);
var agreementString = Newtonsoft.Json.JsonConvert.SerializeObject(agreement, new CustomDateTimeConverter());
var oldAgreementString = Newtonsoft.Json.JsonConvert.SerializeObject(oldAgreement, new CustomDateTimeConverter());
if (agreementString != oldAgreementString)
{
agreementRepository.Update(agreement);
}

Unboxing and casting in one statement in generic method

I have a little utility method that looks like so:
/// <summary>
/// Replaces a DBNull value with the default of the type specified
/// </summary>
/// <typeparam name="T">Resulting type</typeparam>
/// <param name="p_this">Object to check for DBNull</param>
/// <returns>p_this if it is not DBNull.Value, else default(T)</returns>
public static T ReplaceDBNullWithDefault<T>(this object p_this)
{
return p_this == System.DBNull.Value ? default(T) : (T)p_this;
}
In my specific scenario, I am taking a record out of a data table and taking a specific field out of it using weak types, and the specific field I'm getting is a long which is being boxed into an object. An example that reproduces this is as follows:
var obj = 2934L;
int num = obj.ReplaceDBNullWithDefault<int>();
It fails with an InvalidCastException, at (T)p_this.
I understand why, the boxed long cannot be cast directly to int, and trying to do it like this also fails:
object myLong = 234L;
int myInt = (int)myLong;
However, unboxing and then casting works fine:
object myLong = 234L;
int myInt = (int)(long)myLong;
How can I work around this in my method?
You can try this:
public static T ReplaceDBNullWithDefault<T>(this object p_this) where T : struct
{
return
p_this == System.DBNull.Value
? default(T)
: (T)Convert.ChangeType(p_this, typeof(T));
}
Nevertheless you will get an exception if you try to apply this function to a not-convertible type.
So probably it really would be better to cast the value manually to the known type.
You can use this approach:
/// <summary>
/// Replaces a DBNull value with the default of the type specified
/// </summary>
/// <typeparam name="T">Resulting type</typeparam>
/// <param name="value">Object to check for DBNull</param>
/// <param name="tryConvert">if true the object will be converted to the target type if possible, otherwise an InvalidCastException is raised</param>
/// <returns>p_this if it is not DBNull.Value, else default(T)</returns>
/// <exception cref="InvalidCastException">Thrown if the target type is incorrect and the value could not be converted to it</exception>
public static T ReplaceDbNullWithDefault<T>(this object value, bool tryConvert = true)
{
if (value == System.DBNull.Value || value == null)
return default(T);
if (value is T)
return (T) value;
if(!tryConvert || !(value is IConvertible))
throw new InvalidCastException($"Cannot convert {value.GetType()} to {typeof(T)}.");
return (T)((IConvertible) value).ToType(typeof(T), null);
}

How do I create methods at run time in a pre-existing class?

I'm using the fluent pattern for helping with unit testing, and result object building. The biggest pain point of the fluent builder pattern is having to define all these With____ methods for each and every property that I might want to set.
When it comes to an object with maybe 30 fields that I might want to set, I don't exactly want to write out 30 methods that all pretty much do the same thing. I'd rather just write out something dynamic that can handle all the similar logic for me.
For example (psuedo code)
for each property in this.properties
define method( property.name with
return type: this.class,
parameter types: [property.type]){
set property property.name, parameters[0]
return this
}
Here is what I have so far in c#
var properties = typeof(EngineModelBuilder).GetProperties();
foreach (var property in properties){
// how do I create a method here with the property?
// a property has .PropertyType and a .Name
// and the return type is always going to be 'this'
}
For reference, here is how a normal fluent builder method looks:
public EngineModelBuilder WithDescription(string description)
{
_description = description;
return this;
}
This is the class I came up with. It utilizes C#'s dynamic object to use the "method_missing" approach of run-time functionality.
Note that method_missing is from Ruby, and is commonly used for this kind of dynamic behavior.
DynamicBuilder.cs:
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace PGenCore
{
/// <summary>
/// TODO: test different field retreival techniques (using fields from T, and managing in a Dictionary)
/// - how would we define defaults?
///
///
/// Usage:
/// dynamic objectBuilder = new ObjectBuilder();
/// var object = objectBuilder
/// .WithObjectFieldName(appropriateValue)
/// .WithObjectField(appropriateValue2)
/// .Build();
///
/// </summary>
/// <typeparam name="T">Type to Build</typeparam>
public class DynamicBuilder<T> : DynamicObject
{
#region List of FieldInformation
protected FieldInfo[] FieldInfos;
public FieldInfo[] FieldInformation
{
get
{
// don't GetFields all the time
if (FieldInfos != null) return FieldInfos;
FieldInfos = this.GetType().GetFields(
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance);
return FieldInfos;
}
}
#endregion
#region Utility
/// <summary>
/// converts FieldName to _fieldName
/// </summary>
/// <param name="publicName"></param>
/// <returns></returns>
public static string PublicNameToPrivate(string publicName)
{
var propertyLowerFirstLetterName = char.ToLower(
publicName[0]) + publicName.Substring(1);
var privateName = "_" + propertyLowerFirstLetterName;
return privateName;
}
#endregion
#region Method is Missing? Check for With{FieldName} Pattern
/// <summary>
/// Inherited form DynamicObject.
/// Ran before each method call.
///
///
/// Note: Currently only works for setting one value
/// at a time.
/// e.g.: instance.Object = value
/// </summary>
/// <param name="binder"></param>
/// <param name="args"></param>
/// <param name="result"></param>
/// <returns></returns>
public override bool TryInvokeMember(
InvokeMemberBinder binder,
object[] args,
out object result)
{
var firstArgument = args[0];
var methodName = binder.Name;
var propertyRootName = methodName;
// following the builder pattern,
// methods that participate in building T,
// return this so we can chain building methods.
result = this;
// for booleans, since the field / property should be named as
// a question, using "With" doesn't make sense.
// so, this logic is only needed when we are not setting a
// boolean field.
if (!(firstArgument is bool))
{
// if we are not setting a bool, and we aren't starting
// with "With", this method is not part of the
// fluent builder pattern.
if (!methodName.Contains("With")) return false;
propertyRootName = methodName.Replace("With", "");
}
// convert to _privateFieldName
// TODO: think about dynamicly having fields in a Dictionary,
// rather than having to specify them
var builderFieldName = PublicNameToPrivate(propertyRootName);
// find matching field name, given the method name
var fieldInfo = FieldInformation
.FirstOrDefault(
field => field.Name == builderFieldName
);
// if the field was not found, abort
if (fieldInfo == null) return false;
// set the field to the value in args
fieldInfo.SetValue(this, firstArgument);
return true;
}
#endregion
/// <summary>
/// Returns the built object
/// </summary>
/// <returns></returns>
public virtual T Build()
{
throw new NotImplementedException();
}
/// <summary>
/// for any complex associations
/// - building lists of items
/// - building anything else that isn't just an easy vavlue.
/// </summary>
public virtual void SetRelationshipDefaults()
{
throw new NotImplementedException();
}
}
}
Tests of usage can be seen here: https://github.com/NullVoxPopuli/Procedural-Builder/blob/master/ProceduralBuilder.Test/DynamicBuilderTest.cs

Default value of a type at Runtime [duplicate]

This question already has answers here:
how to get the default value of a type if the type is only known as System.Type? [duplicate]
(3 answers)
Closed 9 years ago.
For any given type i want to know its default value.
In C#, there is a keyword called default for doing this like
object obj = default(Decimal);
but I have an instance of Type (called myType) and if I say this,
object obj = default(myType);
it doesn't work
Is there any good way of doing this?
I know that a huge switch block will work but thats not a good choice.
There's really only two possibilities: null for reference types and new myType() for value types (which corresponds to 0 for int, float, etc) So you really only need to account for two cases:
object GetDefaultValue(Type t)
{
if (t.IsValueType)
return Activator.CreateInstance(t);
return null;
}
(Because value types always have a default constructor, that call to Activator.CreateInstance will never fail).
You could also add it as an extension method to System.Type:
public static class TypeExtensions
{
public static object GetDefaultValue(this Type t)
{
if (t.IsValueType && Nullable.GetUnderlyingType(t) == null)
return Activator.CreateInstance(t);
else
return null;
}
}
Having solved this problem in my own systems, here is a method for correctly determining the default value of an arbitrary Type at run time, which has been tested against thousands of Types:
/// <summary>
/// [ <c>public static object GetDefault(this Type type)</c> ]
/// <para></para>
/// Retrieves the default value for a given Type
/// </summary>
/// <param name="type">The Type for which to get the default value</param>
/// <returns>The default value for <paramref name="type"/></returns>
/// <remarks>
/// If a null Type, a reference Type, or a System.Void Type is supplied, this method always returns null. If a value type
/// is supplied which is not publicly visible or which contains generic parameters, this method will fail with an
/// exception.
/// </remarks>
/// <example>
/// To use this method in its native, non-extension form, make a call like:
/// <code>
/// object Default = DefaultValue.GetDefault(someType);
/// </code>
/// To use this method in its Type-extension form, make a call like:
/// <code>
/// object Default = someType.GetDefault();
/// </code>
/// </example>
/// <seealso cref="GetDefault<T>"/>
public static object GetDefault(this Type type)
{
// If no Type was supplied, if the Type was a reference type, or if the Type was a System.Void, return null
if (type == null || !type.IsValueType || type == typeof(void))
return null;
// If the supplied Type has generic parameters, its default value cannot be determined
if (type.ContainsGenericParameters)
throw new ArgumentException(
"{" + MethodInfo.GetCurrentMethod() + "} Error:\n\nThe supplied value type <" + type +
"> contains generic parameters, so the default value cannot be retrieved");
// If the Type is a primitive type, or if it is another publicly-visible value type (i.e. struct/enum), return a
// default instance of the value type
if (type.IsPrimitive || !type.IsNotPublic)
{
try
{
return Activator.CreateInstance(type);
}
catch (Exception e)
{
throw new ArgumentException(
"{" + MethodInfo.GetCurrentMethod() + "} Error:\n\nThe Activator.CreateInstance method could not " +
"create a default instance of the supplied value type <" + type +
"> (Inner Exception message: \"" + e.Message + "\")", e);
}
}
// Fail with exception
throw new ArgumentException("{" + MethodInfo.GetCurrentMethod() + "} Error:\n\nThe supplied value type <" + type +
"> is not a publicly-visible type, so the default value cannot be retrieved");
}
In these examples, the GetDefault method is implemented in the static class DefaultValue. Call this method with a statement like:
object Default = DefaultValue.GetDefault(someType);
To use the GetDefault method as an extension method for Type, call it like this:
object Default = someType.GetDefault();
This second, Type-extension approach is a simpler client-code syntax, since it removes the need to reference the containing DefaultValue class qualifier on the call.
The above run time form of GetDefault works with identical semantics as the primitive C# 'default' keyword, and produces the same results.
To use a generic form of GetDefault, you may access the following function:
/// <summary>
/// [ <c>public static T GetDefault< T >()</c> ]
/// <para></para>
/// Retrieves the default value for a given Type
/// </summary>
/// <typeparam name="T">The Type for which to get the default value</typeparam>
/// <returns>The default value for Type T</returns>
/// <remarks>
/// If a reference Type or a System.Void Type is supplied, this method always returns null. If a value type
/// is supplied which is not publicly visible or which contains generic parameters, this method will fail with an
/// exception.
/// </remarks>
/// <seealso cref="GetDefault(Type)"/>
public static T GetDefault<T>()
{
return (T) GetDefault(typeof(T));
}
A call to the generic form could be something like:
int? inDefaultVal = DefaultValue.GetDefault<int?>();
Of course, the above generic form of GetDefault is unnecessary for C#, since it works the same as default(T). It is only useful for a .NET language that does not support the 'default' keyword but which supports generic types. In most cases, the generic form is unnecessary.
A useful corollary method is one to determine whether an object contains the default value for its Type. I also rely on the following IsObjectSetToDefault method for that purpose:
/// <summary>
/// [ <c>public static bool IsObjectSetToDefault(this Type ObjectType, object ObjectValue)</c> ]
/// <para></para>
/// Reports whether a value of type T (or a null reference of type T) contains the default value for that Type
/// </summary>
/// <remarks>
/// Reports whether the object is empty or unitialized for a reference type or nullable value type (i.e. is null) or
/// whether the object contains a default value for a non-nullable value type (i.e. int = 0, bool = false, etc.)
/// <para></para>
/// NOTE: For non-nullable value types, this method introduces a boxing/unboxing performance penalty.
/// </remarks>
/// <param name="ObjectType">Type of the object to test</param>
/// <param name="ObjectValue">The object value to test, or null for a reference Type or nullable value Type</param>
/// <returns>
/// true = The object contains the default value for its Type.
/// <para></para>
/// false = The object has been changed from its default value.
/// </returns>
public static bool IsObjectSetToDefault(this Type ObjectType, object ObjectValue)
{
// If no ObjectType was supplied, attempt to determine from ObjectValue
if (ObjectType == null)
{
// If no ObjectValue was supplied, abort
if (ObjectValue == null)
{
MethodBase currmethod = MethodInfo.GetCurrentMethod();
string ExceptionMsgPrefix = currmethod.DeclaringType + " {" + currmethod + "} Error:\n\n";
throw new ArgumentNullException(ExceptionMsgPrefix + "Cannot determine the ObjectType from a null Value");
}
// Determine ObjectType from ObjectValue
ObjectType = ObjectValue.GetType();
}
// Get the default value of type ObjectType
object Default = ObjectType.GetDefault();
// If a non-null ObjectValue was supplied, compare Value with its default value and return the result
if (ObjectValue != null)
return ObjectValue.Equals(Default);
// Since a null ObjectValue was supplied, report whether its default value is null
return Default == null;
}
The above IsObjectSetToDefault method can either be called in its native form or accessed as a Type-class extension.
How about something like...
class Program
{
static void Main(string[] args)
{
PrintDefault(typeof(object));
PrintDefault(typeof(string));
PrintDefault(typeof(int));
PrintDefault(typeof(int?));
}
private static void PrintDefault(Type type)
{
Console.WriteLine("default({0}) = {1}", type,
DefaultGenerator.GetDefaultValue(type));
}
}
public class DefaultGenerator
{
public static object GetDefaultValue(Type parameter)
{
var defaultGeneratorType =
typeof(DefaultGenerator<>).MakeGenericType(parameter);
return defaultGeneratorType.InvokeMember(
"GetDefault",
BindingFlags.Static |
BindingFlags.Public |
BindingFlags.InvokeMethod,
null, null, new object[0]);
}
}
public class DefaultGenerator<T>
{
public static T GetDefault()
{
return default(T);
}
}
It produces the following output:
default(System.Object) =
default(System.String) =
default(System.Int32) = 0
default(System.Nullable`1[System.Int32]) =
What do you mean by "Default Value"? All reference Types ("class") have null as default value, while all value types will have their default values according to this table.
Here's a function that will return the default value for a nullable type (in other words, it returns 0 for both Decimal and Decimal?):
public static object DefaultValue(Type maybeNullable)
{
Type underlying = Nullable.GetUnderlyingType(maybeNullable);
if (underlying != null)
return Activator.CreateInstance(underlying);
return Activator.CreateInstance(maybeNullable);
}

How do i use Activator.CreateInstance with strings?

In my reflection code i hit a problem with my generic section of code. Specifically when i use a string.
var oVal = (object)"Test";
var oType = oVal.GetType();
var sz = Activator.CreateInstance(oType, oVal);
Exception
An unhandled exception of type 'System.MissingMethodException' occurred in mscorlib.dll
Additional information: Constructor on type 'System.String' not found.
I tried this for testing purposes and it occurs in this single liner too
var sz = Activator.CreateInstance("".GetType(), "Test");
originally i wrote
var sz = Activator.CreateInstance("".GetType());
but i get this error
Additional information: No parameterless constructor defined for this object.
How do i create a string using reflection?
Keep in mind that the string class is immutable. It cannot be changed after it is created. That explains why it doesn't have a parameterless constructor, it could never generate a useful string object other than an empty string. That's already available in the C# language, it is "".
Same reasoning applies for a string(String) constructor. There is no point in duplicating a string, the string you'd pass to the constructor is already a perfectly good instance of the string.
So fix your problem by testing for the string case:
var oType = oVal.GetType();
if (oType == typeof(string)) return oVal as string;
else return Activator.CreateInstance(oType, oVal);
You are trying to do this :
var sz = new string();
Try to compile it, you will understand your error.
You may try :
var sz = Activator.CreateInstance(typeof(string), new object[] {"value".ToCharArray()});
But it looks useless, you should directly use value...
It looks like you're trying to call a constructor which just takes a string - and there isn't such a constructor. If you've already got a string, why are you trying to create a new one? (When you didn't provide any further arguments, you were trying to call a parameterless constructor - which again, doesn't exist.)
Note that typeof(string) is a simpler way to get a reference to the string type.
Could you give us more information about the bigger picture of what you're trying to do?
String actually has no constructor that takes a string as input. There is a constructor that takes a char array so this should work:
var sz = Activator.CreateInstance ("".GetType (), "Test".ToCharArray ());
This is what I use in my projects. As far as needing to create an instantiation of a type of object and not knowing at design time, is rather normal for me. Perhaps you are cycling through object properties and you want to instantiate all of them dynamically. I have many times needed to create then assign values to non instantiated POCO objects... with the below code you can use a string value stored in the DB to instantiate an object as well or instantiate an object stored in a library that is referencing your library - so you can bypass circular reference errors as well... Hope it helps.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
/// <summary>
/// Instantiates an object. Must pass PropertyType.AssemblyQualifiedName for factory to operate
/// returns instantiated object
/// </summary>
/// <param name="typeName"></param>
/// <returns></returns>
public static object Create(string typeAssemblyQualifiedName)
{
// resolve the type
Type targetType = ResolveType(typeAssemblyQualifiedName);
if (targetType == null)
throw new ArgumentException("Unable to resolve object type: " + typeAssemblyQualifiedName);
return Create(targetType);
}
/// <summary>
/// create by type of T
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T Create<T>()
{
Type targetType = typeof(T);
return (T)Create(targetType);
}
/// <summary>
/// general object creation
/// </summary>
/// <param name="targetType"></param>
/// <returns></returns>
public static object Create(Type targetType)
{
//string test first - it has no parameterless constructor
if (Type.GetTypeCode(targetType) == TypeCode.String)
return string.Empty;
// get the default constructor and instantiate
Type[] types = new Type[0];
ConstructorInfo info = targetType.GetConstructor(types);
object targetObject = null;
if (info == null) //must not have found the constructor
if (targetType.BaseType.UnderlyingSystemType.FullName.Contains("Enum"))
targetObject = Activator.CreateInstance(targetType);
else
throw new ArgumentException("Unable to instantiate type: " + targetType.AssemblyQualifiedName + " - Constructor not found");
else
targetObject = info.Invoke(null);
if (targetObject == null)
throw new ArgumentException("Unable to instantiate type: " + targetType.AssemblyQualifiedName + " - Unknown Error");
return targetObject;
}
/// <summary>
/// Loads the assembly of an object. Must pass PropertyType.AssemblyQualifiedName for factory to operate
/// Returns the object type.
/// </summary>
/// <param name="typeString"></param>
/// <returns></returns>
public static Type ResolveType(string typeAssemblyQualifiedName)
{
int commaIndex = typeAssemblyQualifiedName.IndexOf(",");
string className = typeAssemblyQualifiedName.Substring(0, commaIndex).Trim();
string assemblyName = typeAssemblyQualifiedName.Substring(commaIndex + 1).Trim();
if (className.Contains("[]"))
className.Remove(className.IndexOf("[]"), 2);
// Get the assembly containing the handler
Assembly assembly = null;
try
{
assembly = Assembly.Load(assemblyName);
}
catch
{
try
{
assembly = Assembly.LoadWithPartialName(assemblyName);//yes yes this is obsolete but it is only a backup call
}
catch
{
throw new ArgumentException("Can't load assembly " + assemblyName);
}
}
// Get the handler
return assembly.GetType(className, false, false);
}

Categories