Oto moja metoda rzutowania obiektu, ale nie na zmienną typu ogólnego, a na System.Type
dynamicznie:
Tworzę wyrażenie lambda w czasie wykonywania przy użyciu System.Linq.Expressions
typu Func<object, object>
, który rozpakowuje dane wejściowe, wykonuje pożądaną konwersję typu, a następnie podaje wynik w ramce. Nowy jest potrzebny nie tylko dla wszystkich typów, na które rzutuje się, ale także dla typów, które są rzutowane (z powodu etapu rozpakowywania). Tworzenie tych wyrażeń jest bardzo czasochłonne, ze względu na odbicie, kompilację i dynamiczne budowanie metod wykonywane pod maską. Na szczęście po utworzeniu wyrażenia można wywoływać wielokrotnie i bez nadmiernego obciążenia, więc każdą z nich przechowuję w pamięci podręcznej.
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);
}
Pamiętaj, że to nie jest magia. Przesyłanie nie występuje w kodzie, podobnie jak w przypadku dynamic
słowa kluczowego, konwertowane są tylko podstawowe dane obiektu. W czasie kompilacji wciąż musimy starannie zastanawiać się, jakiego typu może być nasz obiekt, co czyni to rozwiązanie niepraktycznym. Napisałem to jako włamanie do wywoływania operatorów konwersji zdefiniowanych przez dowolne typy, ale być może ktoś może znaleźć lepszy przypadek użycia.