我们简单地将值类型分为5种:整数型,浮点型,布尔型,字符型,再加上一个本属于引用类型的字符串。
由于 C# 是在编译时静态类型化的,因此变量在声明后就无法再次声明,或无法分配另一种类型的值,除非该类型可以隐式转换为变量的类型。
隐式转换:由于这种转换始终会成功且不会导致数据丢失,因此无需使用任何特殊语法。 示例包括从较小整数类型到较大整数类型的转换以及从派生类到基类的转换。
显式转换(强制转换) :必须使用强制转换表达式,才能执行显式转换。 在转换中可能丢失信息时或在出于其他原因转换可能不成功时,必须进行强制转换。 典型的示例包括从数值到精度较低或范围较小的类型的转换和从基类实例到派生类的转换。
上述2种转换就不过多赘述,隐式转换和显式转换都是十分基础的
用户定义的转换:用户定义的转换是使用特殊方法执行,这些方法可定义为在没有基类和派生类关系的自定义类型之间启用显式转换和隐式转换。 有关详细信息,请参阅用户定义转换运算符。
使用帮助程序类进行转换:若要在非兼容类型(如整数和 System.DateTime 对象,或十六进制字符串和字节数组)之间转换,可使用 System.BitConverter 类、System.Convert 类和内置数值类型的 Parse 方法(如 Int32.Parse)。 有关详细信息,请参见如何将字节数组转换为 int、如何将字符串转换为数字和如何在十六进制字符串与数值类型之间转换。
GetNumericValue是char类型提供的方法,用于将字符转换为double值的数字,失败则返回-1.0
令我不解的是,字符类型只能保存0~9之间的数字,不可能保存浮点数,不知为何返回值是double类型的。
public int a = 123;
char tmp;
tmp = a.ToString()[0];
char.GetNumericValue(tmp);// 使用char提供的GetNumericValue方法可以将char转为double的1
Convert类型的转换存在大量重载,基本可以应对所有转换情况
public int a = 123;
char tmp;
tmp = a.ToString()[0];
int b =Convert.ToInt32(tmp); // 使用ToInt32会将字符1转为ASCII码49
int a = 123;
char tmp;
tmp = a.ToString()[0];
int t = tmp - '0'; // 使用char类型进行计算,最后的结果类型是整数型,输出结果是ASCII码相减
// 49 - 48 = 1
字符串转数字是一种比较万能的方法,因为object提供了ToString方法,能够让任何值类型都转化为字符串。
Parse 和 TryParse 方法会忽略字符串开头和末尾的空格,但所有其他字符都必须是组成合适数值类型(int、long、ulong、float、decimal 等)的字符。
char tmp = '1';
int a = Int32.Parse(" -105 "); // a = -105,无视空格
a = Int32.Parse(tmp.ToString()); // a = 1
bool b = Int32.TryParse("200", out a); // a = 200,方法本身返回布尔值,b = true
错误用法:
Int32.Parse(" -1.05 "); //浮点型不能用整型的Parse方法,应该为float.Parse或其他浮点型的Parse方法
Int32.Parse(" 1 05 "); // 数字之间不能有空格
Int32.Parse(" 10e1 "); // 不接受科学计数法,
由于一般的整数类型Int的类型是System.Int32。而一个byte代表8位,所以一个Int32=4个字节,因此如果要字节转整数,一般需要四个四个地转变。
使用BitConverter类来操作字节数组
byte[] bytes = { 0, 0, 0, 25 };
// 此处是根据操作系统来决定字符顺序的
// 不同计算机的字节体系不同,可能高八位,可能低八位
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes);
int i = BitConverter.ToInt32(bytes, 0);
Console.WriteLine("int: {0}", i);
// Output: int: 25
is 运算符检查表达式结果的运行时类型是否与给定类型兼容。 is 运算符还会对照某个模式测试表达式结果。
具有类型测试 is 运算符的表达式具有以下形式
E is T
E is not T
其中E
是返回一个值的表达式,T
是类型或类型参数的名称。 E
不得为匿名方法或 Lambda 表达式。
简单的来说,is判断true对应四种判断
E
为T
类型时T
的派生类,子类,继承类(包括类和接口)时。E
为T
的可为空类型T?
,且E
不为空时E
到T
的转换涉及装箱拆箱时让我们分别看看这四种对应的判断:
当E
为T
类型时:
int a = 0;
if (a is int) // true
{
Debug.Log(a);
}
if (a is long) // false
{
Debug.Log(a);
}
当为T
的派生类,子类,继承类(包括类和接口)时:
class Parent
{
}
interface IDonothing
{
}
class child : Parent, IDonothing
{
}
void Start()
{
child c = new child();
int a = 0;
if (c is Parent) // true
{
Debug.Log(0);
}
if (c is IDonothing) // true
{
Debug.Log(1);
}
}
当E
为T
的可为空类型T?
,且E
不为空时
int? a = null;
if (a is int) // a为int?但为空,false
{
Debug.Log(1);
}
if (a is int?) // a为int?但为空,false
{
Debug.Log(2);
}
int b = 1;
if (b is int) // b为int,true
{
Debug.Log(3);
}
if (b is int?) // b为int,true
{
Debug.Log(4);
}
a = 1;
if (a is int) // a为int?且不为空,true
{
Debug.Log(5);
}
if (a is int?) // a为int?且不为空,true
{
Debug.Log(6);
}
当E
到T
时涉及装箱拆箱时
object O;
int a = 1;
O = a;
if (O is int) // true
{
Debug.Log(1);
}
if (O is int?) // true
{
Debug.Log(2);
}
if (a is object) // true,毕竟object是所有类的父类,此时符合第二条E为T的派生类
{
Debug.Log(3);
}
在检测类型时,is类型会对E类型进行T类型转换来判断是否为T类型,但不对E的本身的类型造成影响。但is类型不会考虑用户自定义的类型转换。
as
运算符将表达式结果显式转换为给定的引用或可以为null
值的类型。 如果无法进行转换,则as
运算符返回null
。 与强制转换表达式 不同,as
运算符永远不会引发异常。
E as T
使用as运算符,与下述三目运算符是一样的:
E is T ? (T)(E) : (T)null
使用as
进行转换,其中类型T
必须是可为null
值的类型
as
运算符仅考虑引用类型、可以为 null
、装箱和取消装箱转换。 不能使用 as
运算符执行用户定义的转换。 为此,请使用强制转换表达式。
object o = new object() as string;
o = "1";
Debug.Log(o.GetType()); // string类型
implicit operator
或 explicit operator
关键字分别用于定义隐式转换或显式转换。 定义转换的类型必须是该转换的源类型或目标类型。 可用两种类型中的任何一种类型来定义两种用户定义类型之间的转换。
using System;
public readonly struct Digit
{
private readonly byte digit;
public Digit(byte digit)
{
if (digit > 9)
{
throw new ArgumentOutOfRangeException(nameof(digit), "Digit cannot be greater than nine.");
}
this.digit = digit;
}
public static implicit operator byte(Digit d) => d.digit;
public static explicit operator Digit(byte b) => new Digit(b);
public override string ToString() => $"{digit}";
}
public static class UserDefinedConversions
{
public static void Main()
{
var d = new Digit(7);
byte number = d;
Console.WriteLine(number); // output: 7
Digit digit = (Digit)number;
Console.WriteLine(digit); // output: 7
}
}
使用自定义类型可以定义隐式转换和显示转换,但是要注意类型匹配。