Aqui está o meu método para converter um objeto, mas não para uma variável de tipo genérico, e sim para uma System.Type
dinâmica:
Crio uma expressão lambda em tempo de execução usando System.Linq.Expressions
, do tipo Func<object, object>
, que desmarca sua entrada, executa a conversão de tipo desejada e, em seguida, fornece o resultado em caixa. Um novo é necessário não apenas para todos os tipos que são convertidos, mas também para os tipos que são convertidos (devido à etapa de remoção da caixa de seleção). Criar essas expressões consome muito tempo, devido à reflexão, à compilação e à construção dinâmica de métodos que são feitas sob o capô. Felizmente, uma vez criadas, as expressões podem ser invocadas repetidamente e sem sobrecarga, então eu cache cada uma.
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);
}
Note que isso não é mágico. A transmissão não ocorre no código, como ocorre com a dynamic
palavra - chave, apenas os dados subjacentes do objeto são convertidos. No momento da compilação, ainda temos que descobrir com precisão qual o tipo de nosso objeto, tornando essa solução impraticável. Eu escrevi isso como um hack para chamar operadores de conversão definidos por tipos arbitrários, mas talvez alguém por aí possa encontrar um melhor caso de uso.