代码中不用明确告诉编译器,你要将一种类型转换成另一种类型,编译器会自动帮我们将这个类型进行转换这种转换叫做隐式类型转换
long类型在内存当中是用八个字节64位储存他的数值
int类型在内存当中是使用四个字节,也就是32位bit来储存他的数值
那么很显然,long类型它能存储的数值范围,要比int类型所能储存的数值范围要大得多
那这个时候如果我们有一个int类型的数值想让他向long类型转换,他的精度完全不会丢失
实例如下:
int x=int.MaxValue; //取int类型的最大值
long y=x; //这里x由int类型隐式转换成了long类型
Console.WriteLine("x="+x); //打印出X的值
Console.WriteLine("y=" + y);//打印出y的值
运行结果
由上图可以看出int x 隐式转换为long类型之后的值没有任何变化,这就是我们在不丢失精度的情况下隐式类型转换
除了int类型可以向long类型进行隐式转换外,还有很多类型可以在不丢失精度的情况下进行隐式类型转换
具体可以查看->
C#语言定义文档
我这里展示C#语言定义文档的部分截图
所有面向对象的语言,都支持子类向父类的隐式类型转换(面向对象的"多态"就是基于我们的面向对象语言支持子类向父类隐式类型转换)
实例:
static void Main(string[] args)
{
Teacher t = new Teacher();//声明一个Teacher类型变量并让其引用一个Teacher类的实例
//Teacher类型变量t所引用的是上面创建的Teacher这个实例所在内存的地址
Human h;//声明一个Human类型变量h
h = t; //将Teacher类型变量t赋值给Human类型变量h
//Human类型变量h接收到的是t索引用的Teacher实例的内存地址
}
class Animal //创建一个Animal类
{
public void Eat() //并创建一个Eat方法
{
Console.WriteLine("Eating...");//打印一行字
}
}
//再创建一个Human类,并继承Animal类
//当你声明一个类的时候,如果你想指定他的基类就在你声明的这个类名称后面加上一个" : ",
//冒号后面跟着基类的名字就好了
//当Animal作为Human基类的时候,那么Animal所有的成员都将被Human继承
class Human : Animal
{
public void Think()
{
Console.WriteLine("Who i am");
}
}
class Teacher : Human //再声明一个Teacher,并继承Human类
{
public void Teach()
{
Console.WriteLine("I teach Programming");
}
}
可以看出将子类 t 直接赋值给父类 h 是可行的(虽然变量h只是获得了变量t的Teacher实例的引用地址),这是因为这里进行了子类向父类的隐式转换
这个时候你使用成员访问操作符分别查看变量t和变量h的话,可以看到t变量能点出eat teach 和think三个方法,而变量h却只能访问到eat 和teach ,按道理来说,他们两个引用的是同一实例
这是因为C#语言规定,当你试图拿一个引用变量去访问它所引用的实例成员的时候,只能访问到这个变量所能访问到的成员,(注意,是只能访问到你这个变量类型所拥有的成员,而不是你变量所引用的实例所具有的成员)
而我们变量h类型是Human,由上面的代码可以看出Human具有Think这个方法,而Human派生自Animal 这个类,所以它又具有Animal 类里面的Eat方法,所以,当你试图使用成员访问操作符去访问变量h的时候,只能访问到变量h类型所具有的Think和Eat方法
Teacher t = new Teacher();//声明一个Teacher类型变量并让其引用一个Teacher类的实例
//Teacher类型变量t所引用的是上面创建的Teacher这个实例所在内存的地址
Human h;
h = t;
Animal a = t; //将t赋值给a
a.
如上图,同理,当我们将t所引用的实例地址给Animal 类型的变量a时
a也只能访问到Animal 类型所具有的成员
使用方法 (t)x 即 cast 括号里面的t是你要转换的类型 x是你要转换的变量,实例如下
uint x=100; //声明一个uint类型的变量x并赋值
ushort =y; //申明一个ushort类型的变量y
y=(ushort )x ;//使用强制转换将uint类型变量x转换成ushort类型并赋值给ushort类型变量y
Console.WriteLine(y);//查看y值赋值成功了没
// 输出是100,成功
实例
//查看ushort类型在最大值
Console.WriteLine(ushort.MaxValue);//ushort类型最大值为65535
//声明一个uint类型的值,让他刚好超出ushort类型的最大值大一
uint x = 65536;//刚好比ushort最大值大一位
//使用显示转换将x赋值给一个ushort类型的变量
ushort y = (ushort)x;
//查看强制转换后赋值给y的值发生了哪些变化
Console.WriteLine(y);
string xStr = Convert.ToString(x, 2).PadLeft(32, '0');
string yStr = Convert.ToString(y, 2).PadLeft(32, '0');
这是因为ushort是16位bit表示正整数,那么最大值在二进制内存储的值是"1111111111111111",也就是65535
这个时候再给他赋值uint类型的65536"
uint是用32位bit位表示正整数的,那么他在二进制内存储存的值为"00000000000000010000000000000000"
也就是说,ushort装不下那么多位bit,所以它会将值截断成自己能装下的16数bit
因为是从后面开始截取的,所以"00000000000000010000000000000000"截取后就变成了"000000000000000"
代码验证如下
//打印出ushort类型在最大值
Console.WriteLine("ushort类型最大值="+ushort.MaxValue);//ushort类型最大值为65535
//声明一个uint类型的值,让他刚好超出ushort类型的最大值大一
uint x = 65536;//刚好比ushort最大值大一位
//使用显示转换将x赋值给一个ushort类型的变量
ushort y = (ushort)x;
//打印出y值
Console.WriteLine("y值="+y);
//打印出x值在内存中的bit位表示
string xStr = Convert.ToString(x, 2).PadLeft(32, '0');
//因为ToString所转化前的值是数值类型,所以0会被舍弃,这里添加PadLeft方法将被舍弃的0补回来
//查看y在内存中的数值表示
//这里显示的是y在内存中以16位bit储存的值,为了方便对比,使用*将其补齐位32位
string ystr = Convert.ToString(y, 2).PadLeft(16, '0').PadLeft(32, '*');
Console.WriteLine(xStr+"===="+"uint类型变量x在内存中的值");
Console.WriteLine(ystr+"===="+ "ushort类型变量Y在内存中的值使用*补齐32位" );
效果图,可以看出截断的二进制值为"000000000000000",所以"y=0"
有些数据类型不能使用cast这种形式来进行转换,比如string转换成int,这个时候我们就需要使用一些工具类来进行转换了
你几乎能使用Convert类来转换任何类型
示例如下
string a = "12345"; //声明一个string类型的变量并给他赋值12345
double b = Convert.ToDouble(a);//调用conver类里面的ToDouble方法将变量a的类型转换为doubel,并赋值给变量b
Console.WriteLine(b);//输出
在有些时候,我们也需要将数值类型的数据转化成字符串类型的数据当我们遇到这种情况的时候,就有两种方法来进行转化,一种是上面的调用Console类里面的ToString方法,还有一种就是调用我们数值类型的ToString实例方法
示例如下
先使用wpf创建一个带button和TextBox的窗体
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto">RowDefinition>
<RowDefinition Height="auto">RowDefinition>
<RowDefinition Height="auto">RowDefinition>
<RowDefinition Height="auto">RowDefinition>
<RowDefinition Height="auto">RowDefinition>
<RowDefinition Height="auto">RowDefinition>
Grid.RowDefinitions>
<TextBox x:Name="myTextBox1" Grid.Row="0">TextBox>
<TextBox x:Name="myTextBox2" Grid.Row="2">TextBox>
<TextBox x:Name="myTextBox3" Grid.Row="4">TextBox>
<Button x:Name="myButton1" Content="Click Me1!" Grid.Row="1">Button>
<Button x:Name="myButton2" Content="Click Me2!" Grid.Row="3" >Button>
<Button x:Name="myButton3" Content="Click Me3!" Grid.Row="5">Button>
Grid>
public MainWindow()
{
InitializeComponent();
this.myButton1.Click += myButton_Click1;
this.myButton2.Click += delegate (object sender, RoutedEventArgs e)
{
double x = double.Parse(this.myTextBox1.Text);
double y = double.Parse(this.myTextBox2.Text);
//parse的缺点,parse只能解析正确的字符串格式类型
double result = x + y;
this.myTextBox3.Text = result.ToString();
};
this.myButton3.Click += (a, b) =>
{
double x = System.Convert.ToDouble(this.myTextBox1.Text);
double y = System.Convert.ToDouble(this.myTextBox2.Text);
double result = x + y;
this.myTextBox3.Text = result.ToString();
};
}
private void myButton_Click1(object sender, RoutedEventArgs e)
{
double x = System.Convert.ToDouble(this.myTextBox1.Text);
double y = System.Convert.ToDouble(this.myTextBox2.Text);
double result = x + y;
this.myTextBox3.Text = System.Convert.ToString(result);
}
class Program
{
static void Main(string[] args)
{
YearsOld yearsOld = new YearsOld();//创建YearsOld类的实例
yearsOld.Age = 3600;//给YearsOld 类型属性Age赋值
Koshi zhangJiao = (Koshi)yearsOld;//使用(T)x即cast转换
//编译器报错,无法将类型Console1.yearsOld转换为Console1.Koshi
}
}
class YearsOld //创建一个类,并创建int类型属性Age
{
public int Age;
}
class Koshi //创建一个类,并创建int类型属性Age
{
public int Age;
}
如上实例,这个时候就需要我们自定义类型转换操作符
class Program
{
static void Main(string[] args)
{
YearsOld yearsOld = new YearsOld();
yearsOld.Age = 3600;
Koshi zhangJiao = (Koshi)yearsOld;
Console.WriteLine(zhangJiao.Age);
}//Koshi
}
class YearsOld
{
public int Age;
//定义自定义类型转换操作符需要的四个修饰符
//public 公共的
//static静态的
//explicit 显示类型转换
//operator 运算符
如果我们把前面的修饰符都忽略掉的话,Koshi(YearsOld yearsOld){},
是不是和Koshi的构造器一样?,,显式类型转换操作符是一个目标类型的实例构造器,只不过它不是写在目标类型里面,而是写在被转换的数据类型里面
//
//目标类型 Koshi 被操作的类型YearsOld 被操作变量yearsOld
public static explicit operator Koshi(YearsOld yearsOld) {
Koshi k = new Koshi();//实例化Koshi
k.Age = yearsOld.Age / 60;//定义Koshi的Age属性等于yearsOld的60个Age属性
return k;//输出转换好的数据
}
}
class Koshi
{
public int Age;
}
显式自定义类型转换操作符已经写好了,那隐式的呢?
隐式的和显式的没很大区别,格式一样,只是要把修饰符explicit改为implicit
示例如下:
class Program
{
static void Main(string[] args)
{
YearsOld yearsOld = new YearsOld();
yearsOld.Age = 3600;
Koshi zhangJiao =yearsOld;//因为是隐式的,所以这里就不需要使用(T)x方式来转换了
Console.WriteLine(zhangJiao.Age);
}//Koshi
}
class YearsOld
{
public int Age;
//将修饰符explicit 改为implicit 就好了
public static implicit operator Koshi(YearsOld yearsOld) {
Koshi k = new Koshi();
k.Age = yearsOld.Age / 60;
return k;
}
}
class Koshi
{
public int Age;
}