(1. Version)
Arrays, Listen bzw. IEnumerables können konvertiert werden.
Von einem Typ in den anderen.
Selbst wenn die Klasse keinen entsprechenden AddRange-Befehl oder Konstruktor hat, ist das auch möglich.
Ich muss also nicht mehr schreiben:
Wenn z.B.
//Complex conversions
char[] a = new char[] { 'm', 'u', 'l', 't', 'u', 'm', 'e', 's', 'c' };
byte[] b = new byte[] { 65, 66, 66, 65, 65, 66, 65, 66 };
int[] resultIntArrayFromCharArray = (int[])typeof(int[]).Cast(a);
int[] resultIntArrayFromByteArray = (int[])typeof(int[]).Cast(b);
char[] resultCharArray = (char[])typeof(char[]).Cast(b);
byte[] resultByteArray = (byte[])typeof(byte[]).Cast(a);
//--------------------------------------------------------------------------
//Convert from IEnumerable<Guid> to ObservableCollection<Guid>
IEnumerable<Guid> guids = new Guid[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() };
ObservableCollection<Guid> observableCollectionGuid = (ObservableCollection<Guid>)typeof(ObservableCollection<Guid>).Cast(guids);
//Convert from ObservableCollection<Guid> to IEnumerable<Guid>
ObservableCollection<Guid> observableCollectionGuid2 = new ObservableCollection<Guid>(new Guid[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() });
IEnumerable<Guid> guids2 = (IEnumerable<Guid>)typeof(IEnumerable<Guid>).Cast(observableCollectionGuid2);
//--------------------------------------------------------------------------
//Simple conversion
int intValue = 339;
double? doubleValueCastedNullable = (double?)typeof(double?).Cast(intValue);
intValue = 90943;
double doubleValueCasted = (double)typeof(double).Cast(intValue);
double doubleValue = 7.0d;
float floatValueCasted = (float)typeof(float).Cast(doubleValue);
float floatValue = 3.09f;
decimal decimalValueCasted = (decimal)typeof(decimal).Cast(floatValue);
//--------------------------------------------------------------------------
try
{
//at the moment an invalid cast exception is expected, when casting an array to one element
string[] textValues = new string[] { "Hallo", "Hello", "Hola", "olá", "buna", "jak", "dag" };
string sText = (string)typeof(string).Cast(textValues);
}
catch (InvalidCastException ex)
{
//so now we get an invalid cast
}
catch (Exception ex)
{
}
//This will be casted, but at the moment makes no sense at all.
//So one shouldn't do this.
try
{
byte[] intValues = new byte[] { 7, 3, 9, 8, 5, 9 };
int value = (int)typeof(int).Cast(intValue);
}
catch (InvalidCastException ex)
{
}
catch (Exception ex)
{
}
//--------------------------------------------------------------------------
//This is possible: cast a single value to a list
string textValue = "Hallo";
List<string> sText2 = (List<string>)typeof(List<string>).Cast(textValue);
//This is possible: cast a single value to a list
Guid singleGuid = Guid.NewGuid();
List<Guid> guidsOfSingleGuid = (List<Guid>)typeof(List<Guid>).Cast(singleGuid);
intValue = 737;
List<int> intsOfSingleInt = (List<int>)typeof(List<int>).Cast(intValue);
bool trueValue = true;
List<bool> boolsOfSingleBool = (List<bool>)typeof(List<bool>).Cast(trueValue);
//--------------------------------------------------------------------------
//This is also possible: Convert object to string: internally call object.ToString()
intValue = 3457;
string intValueCastedToString = (string)typeof(string).Cast(intValue);
using System;
using System.Runtime.CompilerServices;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using DynamicFramework.Iterators;
namespace DynamicFramework.TypeCast
{
/// <summary>
/// Use this class to do any type casts that would consume programming and code in one line.
/// even casting like this is allowed:
///
///
///
/// </summary>
public static class TypeCast
{
// This is the method exposing the rest of the functionality
/// <summary>
/// Casts the specified type.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="obj">The object.</param>
/// <returns></returns>
public static object Cast(this Type type, object obj)
{
return GetConverter(type, obj)(obj);
}
/// <summary>
/// Converters contains the cached converters,
/// so using once it might be slow, the second time a cached converter
/// will be used if possible.
/// </summary>
private static readonly IDictionary<PairOfTypes, Func<object, object>> converters =
new Dictionary<PairOfTypes, Func<object, object>>();
private static readonly ParameterExpression convParameter =
Expression.Parameter(typeof(object), "val");
/// <summary>
/// Gets the converter.
/// </summary>
/// <param name="targetType">Type of the target.</param>
/// <param name="val">The value.</param>
/// <returns></returns>
/// This is the method with the "guts" of the implementation
[MethodImpl(MethodImplOptions.Synchronized)]
private static Func<object, object> GetConverter(Type targetType, object val)
{
var fromType = val != null ? val.GetType() : typeof(object);
var key = new PairOfTypes(fromType, targetType);
Func<object, object> res;
if (converters.TryGetValue(key, out res))
{
return res;
}
bool bConverted = true;
try
{
res = (Func<object, object>)Expression.Lambda(
Expression.Convert(
Expression.Convert(
Expression.Convert(
convParameter
, fromType
)
, targetType
)
, typeof(object)
)
, convParameter
).Compile();
converters.Add(key, res);
}
catch (InvalidOperationException ex)
{
bConverted = false;
}
catch (Exception ex)
{
bConverted = false;
}
if (!bConverted)
{
IList listTargetType = null;
IEnumerable listSourceType = val as IEnumerable;
if (listSourceType != null)
{
if (targetType.IsArray)
{
//TODO: for silverlight, what to do if there is an interface...
#if !SILVERLIGHT
if (listSourceType.GetType().GetInterface(typeof(IList).Name) != null)
{
IList list = (IList)listSourceType;
int count = list.Count;
listTargetType = (IList)Activator.CreateInstance(targetType, count);
int i = 0;
foreach (object oElement in Iter.All(listSourceType))
{
//unbox if needed, don't know yet, how to do by reflection
if (oElement.GetType() == typeof(char) && GetBaseTypeOfGenericIEnumerableType(listTargetType.GetType()) == typeof(byte))
{
listTargetType[i++] = (byte)(char)oElement;
}
else
{
listTargetType[i++] = oElement;
}
}
}
#endif
}
else
{
if (targetType == typeof(string))
{
throw new InvalidCastException(); //this is invalid, because one doesn't know how to convert an array into one element here.
}
listTargetType = (IList)Activator.CreateInstance(targetType);
if (val.GetType() == typeof(string))
{
listTargetType.Add(val);
}
else
{
foreach (object oElement in listSourceType)
{
listTargetType.Add(oElement);
}
}
}
//still null? consider case converting ONE element on source into list of elements in target
}
else
{
if (targetType.FullName.Contains(val.GetType().FullName))
{
Type baseType = GetBaseTypeOfGenericIEnumerableType(targetType);
listTargetType = (IList)Activator.CreateInstance(targetType);
listTargetType.Add(val);
}
}
if (targetType == typeof(string) && listTargetType == null)
{
res = (Func<object, object>)(x => val.ToString());
converters.Add(key, res);
return res;
}
else if (targetType.IsGenericType
&& listTargetType == null
&& targetType.Name.Contains("List`1"))
{
listTargetType = (IList)Activator.CreateInstance(targetType);
listTargetType.Add(val);
}
res = (Func<object, object>)(x => listTargetType); //this will get us what we want
//converters.Add(key, res);
}
return res;
}
//TODO: avoid this method, if possible, but for the moment it's perfect.
/// <summary>
/// Found no other way to do this yet.
/// </summary>
/// <param name="targetType"></param>
/// <returns></returns>
public static Type GetBaseTypeOfGenericIEnumerableType(Type targetType)
{
string[] elements = System.Text.RegularExpressions.Regex.Split(targetType.FullName, @",|\[\[");
if (elements.Length > 1)
{
return Type.GetType(elements[1]);
}
else
{
return Type.GetType(elements[0].TrimEnd(']').TrimEnd('['));
}
}
#if !FRAMEWORK35
/// <summary>
/// Converts the specified original.
/// </summary>
/// <param name="original">The original.</param>
/// <returns></returns>
public static ObservableCollection<object> Convert(IEnumerable original)
{
return new ObservableCollection<object>(original.Cast<object>());
}
/// <summary>
/// Converts the specified original.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="original">The original.</param>
/// <returns></returns>
public static ObservableCollection<T> Convert<T>(IEnumerable<T> original)
{
return new ObservableCollection<T>(original);
}
/// <summary>
/// Converts the specified original.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="original">The original.</param>
/// <returns></returns>
public static ObservableCollection<T> Convert<T>(IEnumerable original)
{
return new ObservableCollection<T>(original.Cast<T>());
}
#endif
/// <summary>
/// Find out how to really unbox!!!
/// </summary>
/// <param name="oElement"></param>
/// <param name="sourceType"></param>
/// <param name="destinationType"></param>
/// <returns></returns>
private static object Unbox(object oElement, Type sourceType, Type destinationType)
{
if (sourceType == typeof(char) && destinationType == typeof(byte))
{
oElement = (byte)(char)oElement;
}
return oElement;
}
// This class provides Equals and GetHashCode
// for a pair of System.Type objects.
private class PairOfTypes
{
private readonly Type first;
private readonly Type second;
public PairOfTypes(Type first, Type second)
{
this.first = first;
this.second = second;
}
public override int GetHashCode()
{
return 31 * first.GetHashCode() + second.GetHashCode();
}
public override bool Equals(object obj)
{
if (obj == this)
{
return true;
}
var other = obj as PairOfTypes;
if (other == null)
{
return false;
}
return first.Equals(other.first)
&& second.Equals(other.second);
}
}
}
}