This isn't urgent, it is more along the lines of trivia or a challenge. The solution works fine as it is, but I suspect it could be better.
What follows is a method I came up with a while back in a rather ugly situation where I need to make a "best effort" to try casting an object of an unrestricted unknown type TO an unrestricted unknown type. The code has just been bugging me. It seems that there should be a more elegant way to do this, but I wanted to get that "Best Effort" part right.
The methods follows the "Try" convention. It accepts an object "value" and an out param of type T, "result." It attempts to cast value into result as type T. If it succeeds, it returns true. If it cannot, it sets result = default(T) and returns false.
It feels like I'm going to lots of trouble in the method. I'd be open to suggestions to streamline this a bit. Comments included here are mostly not in the original... just to explain why a few things were done the way they were done.
/// <summary>
/// Tries to cast <paramref name="value" /> to an instance of type <typeparamref name="T" /> .
/// </summary>
/// <typeparam name="T"> The type of the instance to return. </typeparam>
/// <param name="value"> The value to cast. </param>
/// <param name="result"> When this method returns true, contains <paramref name="value" /> cast as an instance of <typeparamref
/// name="T" /> . When the method returns false, contains default(T). </param>
/// <returns> True if <paramref name="value" /> is an instance of type <typeparamref name="T" /> ; otherwise, false. </returns>
public static bool TryCast<T>(this object value, out T result)
{
var destinationType = typeof(T);
var inputIsNull = (value == null || value == DBNull.Value);
/*
* If the given value is null, we'd normally set result to null and be done with it.
* HOWEVER, if T is not a nullable type, then we can't REALLY cast null to that type, so
* TryCast should return false.
*/
if (inputIsNull)
{
// If T is nullable, this will result in a null value in result.
// Otherwise this will result in a default instance in result.
result = default(T);
// If the input is null and T is nullable, we report success. Otherwise we report failure.
return destinationType.IsNullable();
}
// Convert.ChangeType fails when the destination type is nullable. If T is nullable we use the underlying type.
var underlyingType = Nullable.GetUnderlyingType(destinationType) ?? destinationType;
try
{
/*
* At the moment I cannot remember why I handled Guid as a separate case, but
* I must have been having problems with it at the time or I'd not have bothered.
*/
if (underlyingType == typeof(Guid))
{
if (value is string)
{
value = new Guid(value as string);
}
if (value is byte[])
{
value = new Guid(value as byte[]);
}
result = (T)Convert.ChangeType(value, underlyingType);
return true;
}
result = (T)Convert.ChangeType(value, underlyingType);
return true;
}
catch (Exception ex)
{
// This was originally used to help me figure out why some types weren't casting in Convert.ChangeType.
// It could be removed, but you never know, somebody might comment on a better way to do THAT to.
var traceMessage = ex is InvalidCastException || ex is FormatException || ex is OverflowException
? string.Format("The given value {0} could not be cast as Type {1}.", value, underlyingType.FullName)
: ex.Message;
Trace.WriteLine(traceMessage);
result = default(T);
return false;
}
}
Try
version because we have a generalized Attempt mechanism: goo.gl/DfWwYe \$\endgroup\$