Background
Two popular solutions to the problem of type conversion are to use System.Convert.ChangeType
, or to obtain System.ComponentModel.TypeConverter
and call its ConvertFrom
method. The first method breaks when you try converting a value type T
to System.Nullable<T>
; the second one breaks when you try converting different numeric types, for example, float
to double
. These limitations appear especially frustrating, because the CLR has built-in capabilities to perform both types of conversion.
One way of using these type casting capabilities is to build a LINQ lambda expression, compile it into a Func<object,object>
, and then use the compiled delegate every time we need to convert between two types.
public static class TypeCast {
// This is the method exposing the rest of the functionality
public static object Cast(this Type type, object obj) {
return GetConverter(type, obj)(obj);
}
private static readonly IDictionary<PairOfTypes,Func<object,object>> converters =
new Dictionary<PairOfTypes,Func<object,object>>();
private static readonly ParameterExpression convParameter =
Expression.Parameter(typeof(object), "val");
// This is the method with the "guts" of the implementation
[MethodImpl(MethodImplOptions.Synchronized)]
private static Func<object,object> GetConverter(Type targetType, object val) {
var fromType = val != null ? val.GetType() : typeof(object);
var key = new PairOfTypes(fromType, targetType);
Func<object,object> res;
if (converters.TryGetValue(key, out res)) {
return res;
}
res = (Func<object,object>)Expression.Lambda(
Expression.Convert(
Expression.Convert(
Expression.Convert(
convParameter
, fromType
)
, targetType
)
, typeof(object)
)
, convParameter
).Compile();
converters.Add(key, res);
return res;
}
// This class provides Equals and GetHashCode
// for a pair of System.Type objects.
private class PairOfTypes {
private readonly Type first;
private readonly Type second;
public PairOfTypes(Type first, Type second) {
this.first = first;
this.second = second;
}
public override int GetHashCode() {
return 31*first.GetHashCode() + second.GetHashCode();
}
public override bool Equals(object obj) {
if (obj == this) {
return true;
}
var other = obj as PairOfTypes;
if (other == null) {
return false;
}
return first.Equals(other.first)
&& second.Equals(other.second);
}
}
}
Now, you can use the Cast method like this:
double? x = typeof(double?).Cast(1.0);
int y = typeof(int).Cast(1.2345);
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!