Berikut adalah metode saya untuk melemparkan objek tetapi tidak ke variabel tipe generik, bukan ke System.Type
dinamis:
Saya membuat ekspresi lambda pada saat run-time menggunakan System.Linq.Expressions
, tipe Func<object, object>
, yang membuka kotak inputnya, melakukan konversi tipe yang diinginkan kemudian memberikan hasilnya kotak. Yang baru diperlukan tidak hanya untuk semua jenis yang dicasting, tetapi juga untuk jenis yang dicasting (karena langkah unboxing). Menciptakan ekspresi ini sangat memakan waktu, karena refleksi, kompilasi dan metode dinamis yang dilakukan di bawah tenda. Untungnya sekali dibuat, ekspresi dapat dipanggil berulang kali dan tanpa overhead tinggi, jadi saya cache masing-masing.
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);
}
Perhatikan bahwa ini bukan sihir. Casting tidak terjadi dalam kode, seperti halnya dengan dynamic
kata kunci, hanya data yang mendasari objek yang akan dikonversi. Pada waktu kompilasi kita masih harus bersusah payah mencari tahu dengan tepat apa jenis objek kita, membuat solusi ini tidak praktis. Saya menulis ini sebagai peretasan untuk memanggil operator konversi yang ditentukan oleh jenis arbitrer, tetapi mungkin seseorang di luar sana dapat menemukan use case yang lebih baik.