类型转换是将一个数据类型的值转换为另一个数据类型的过程
.NET是一个强类型的语言,类型转换是一个常见的操作
特别是在底层框架或者中间件的开发中,存在很多反射和动态编程的场景
所以类型转换也是.NET开发中的一个重要话题。
类型转换的场景:
- 不同语言间的数据交互
- Entity与DTO转换
- 反射/动态构建对象
.NET 类型转换方法有哪些?
- 隐式转换:由于这种转换始终会成功且不会导致数据丢失,因此无需使用任何特殊语法
C#
int i = 1;
float f = i;
- 显示转换(强制转换):必须使用强制转换表达式,才能执行显示转换。在转换中可能丢失信息时或在出于其他原因转换可能不成功时,必须进行强制转换。
C#
float f = 18f;
int i = (int)f;
- 用户重写转换:用户定义的转换是使用特殊方法执行,这些方法可定义为在没有基类和派生类关系的自定义类型之间启用显示转换和隐式转换。
C#
public readonly struct Change(string name)
{
private readonly string _name = name;
//自定义隐式转换
public static implicit operator string(Change change) => change._name;
//自定义显示转换
public static explicit operator Change(string name) => new Change(name);
}
string names = "Bob";
//显式转换
Change cc = (Change)names;
//隐式转换
string bc = cc;
- 使用帮助程序类:若要在非兼容类型(如整数和DateTime对象,或十六进制字符串和字节数组)之间转换,可使用BitConverter类、Convert类和内置数值类型的Parse方法(如 int.Parse)
C#
var s = "2019-09-14 19:05:00";
var time = DateTime.Parse(s);
- as和is运算符:严格意义上来说不属于类型转换,只是检查是否属于这个类型
- is运算符检查表达式结果的运行时类型是否与给定类型兼容
- as运算符将表达式结果显式转换为给定的引用或可以为null值的类型。如果无法进行转换,则as运算符返回null。与强制转换表达式不同,as运算符永远不会引发异常
is
C#
var obj = (int)1;
Console.WriteLine(obj is object);
Console.WriteLine(obj is IConvertible);
Console.WriteLine(obj is int);
Console.WriteLine(obj is float);
as
C#
var obj = (int)1;
Console.WriteLine(obj as object);
Console.WriteLine(obj as IConvertible);
Console.WriteLine(obj as int?);
Console.WriteLine(obj as float?);
- Dynamic动态类型的类型转换
C#
public class MyDynamic(object value) : IDynamicMetaObjectProvider
{
public object value { get; } = value;
public DynamicMetaObject GetMetaObject(Expression parameter)
=> new MyDynamicMetaObject(parameter,BindingRestrictions.Empty, this.value);
}
public class MyDynamicMetaObject(Expression expression,BindingRestrictions restrictions,object value):DynamicMetaObject(expression,restrictions,value)
{
public override DynamicMetaObject BindConvert(ConvertBinder binder)
{
var res = Convert.ChangeType(value, binder.Type);
var expr = Expression.Convert(Expression.Constant(res),binder.Type);
return new DynamicMetaObject(expr,BindingRestrictions.GetTypeRestriction(res,binder.Type));
}
}
dynamic my = new MyDynamic(4561);
int i = my;
- IParsable<TSelf> :在C#11中,引入了接口中的静态虚拟成员概念,这使得接口可以声明静态抽象方法
C#
var a = "1".Parse<int>();
static class IParseable
{
public static T Parse<T>(this string input) where T : IParsable<T>
{
return T.Parse(input, CultureInfo.InvariantCulture);
}
}
在日常开发中的类型转换
C#
public class Convert()
{
public static int Toint(this object obj, int defaultVal = 0)
{
if (obj == null)
{
return defaultVal;
}
if (int.TryParse(obj.ToString(),out int retal))
{
retal = defaultVal;
}
return retal;
}
}