Вот мой метод приведения объекта, но не к переменной общего типа, а к System.Type
динамически:
Я создаю лямбда-выражение во время выполнения, используя System.Linq.Expressions
тип Func<object, object>
, который распаковывает входные данные, выполняет желаемое преобразование типов, а затем дает результат в штучной упаковке. Новый нужен не только для всех типов, которые подвергаются приведениям, но также и для типов, которые подвергаются приведению (из-за шага распаковки). Создание этих выражений отнимает много времени из-за рефлексии, компиляции и динамического построения метода, который делается под капотом. К счастью, после создания выражения можно вызывать многократно и без больших накладных расходов, поэтому я кеширую каждое из них.
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);
}
Обратите внимание, что это не волшебство. Приведение не происходит в коде, как это происходит с dynamic
ключевым словом, конвертируются только базовые данные объекта. Во время компиляции нам все еще приходится тщательно выяснять, какого типа может быть наш объект, что делает это решение непрактичным. Я написал это как хак для вызова операторов преобразования, определенных произвольными типами, но, возможно, кто-нибудь найдет лучший вариант использования.