Voici ma méthode pour convertir un objet mais pas en une variable de type générique, plutôt en une System.Type
dynamique:
Je crée une expression lambda au moment de l'exécution en utilisant System.Linq.Expressions
, de type Func<object, object>
, qui déballe son entrée, effectue la conversion de type souhaitée puis donne le résultat encadré. Un nouveau est nécessaire non seulement pour tous les types qui sont castés, mais aussi pour les types qui sont castés (en raison de l'étape de déballage). La création de ces expressions prend beaucoup de temps, en raison de la réflexion, de la compilation et de la construction de méthode dynamique qui se fait sous le capot. Heureusement, une fois créées, les expressions peuvent être invoquées à plusieurs reprises et sans surcharge, donc je mets chacune en cache.
private static Func<object, object> MakeCastDelegate(Type from, Type to)
{
var p = Expression.Parameter(typeof(object)); //do not inline
return Expression.Lambda<Func<object, object>>(
Expression.Convert(Expression.ConvertChecked(Expression.Convert(p, from), to), typeof(object)),
p).Compile();
}
private static readonly Dictionary<Tuple<Type, Type>, Func<object, object>> CastCache
= new Dictionary<Tuple<Type, Type>, Func<object, object>>();
public static Func<object, object> GetCastDelegate(Type from, Type to)
{
lock (CastCache)
{
var key = new Tuple<Type, Type>(from, to);
Func<object, object> cast_delegate;
if (!CastCache.TryGetValue(key, out cast_delegate))
{
cast_delegate = MakeCastDelegate(from, to);
CastCache.Add(key, cast_delegate);
}
return cast_delegate;
}
}
public static object Cast(Type t, object o)
{
return GetCastDelegate(o.GetType(), t).Invoke(o);
}
Notez que ce n'est pas magique. La conversion ne se produit pas dans le code, comme c'est le cas avec le dynamic
mot clé, seules les données sous-jacentes de l'objet sont converties. Au moment de la compilation, il nous reste à déterminer minutieusement exactement quel type notre objet pourrait être, ce qui rend cette solution impraticable. J'ai écrit cela comme un hack pour invoquer des opérateurs de conversion définis par des types arbitraires, mais peut-être que quelqu'un peut trouver un meilleur cas d'utilisation.