c#数据类型和类型转换
C# 数据类型
在 C# 中,变量分为以下几种类型:
- 值类型(Value types)
- 引用类型(Reference types)
- 指针类型(Pointer types)
值类型(Value types)
值类型变量可以直接分配给一个值。它们是从类 System.ValueType 中派生的。
值类型直接包含数据。比如 int、char、float,它们分别存储数字、字符、浮点数。当您声明一个 int 类型时,系统分配内存来存储值。
下表列出了 C# 2010 中可用的值类型:
如需得到一个类型或一个变量在特定平台上的准确尺寸,可以使用 sizeof 方法。表达式 sizeof(type) 产生以字节为单位存储对象或类型的存储尺寸。下面举例获取任何机器上 int 类型的存储尺寸:
using System; namespace DataTypeApplication { class Program { static void Main(string[] args) { Console.WriteLine("Size of int: {0}", sizeof(int)); Console.ReadLine(); } } }
当上面的代码被编译和执行时,它会产生下列结果:
Size of int: 4
引用类型(Reference types)
引用类型不包含存储在变量中的实际数据,但它们包含对变量的引用。
换句话说,它们指的是一个内存位置。使用多个变量时,引用类型可以指向一个内存位置。如果内存位置的数据是由一个变量改变的,其他变量会自动反映这种值的变化。内置的 引用类型有:object、dynamic 和 string。
对象(Object)类型
对象(Object)类型 是 C# 通用类型系统(Common Type System - CTS)中所有数据类型的终极基类。Object 是 System.Object 类的别名。所以对象(Object)类型可以被分配任何其他类型(值类型、引用类型、预定义类型或用户自定义类型)的值。但是,在分配值之前,需要先进行类型转换。
当一个值类型转换为对象类型时,则被称为 装箱;另一方面,当一个对象类型转换为值类型时,则被称为 拆箱。
object obj;
obj = 100; // 这是装箱
动态(Dynamic)类型
您可以存储任何类型的值在动态数据类型变量中。这些变量的类型检查是在运行时发生的。
声明动态类型的语法:
dynamic <variable_name> = value;
例如:
dynamic d = 20;
动态类型与对象类型相似,但是对象类型变量的类型检查是在编译时发生的,而动态类型变量的类型检查是在运行时发生的。
字符串(String)类型
字符串(String)类型 允许您给变量分配任何字符串值。字符串(String)类型是 System.String 类的别名。它是从对象(Object)类型派生的。字符串(String)类型的值可以通过两种形式进行分配:引号和 @引号。
例如:
String str = "csharp.com";
一个 @引号字符串:
@"csharp.com";
C# string 字符串的前面可以加 @(称作"逐字字符串")将转义字符(\)当作普通字符对待,比如:
string str = @"C:\Windows";
等价于:
string str = "C:\\Windows";
@ 字符串中可以任意换行,换行符及缩进空格都计算在字符串长度之内。
string str = @"<script type=""text/javascript"">
<!--
-->
</script>";
用户自定义引用类型有:class、interface 或 delegate。
指针类型(Pointer types)
指针类型变量存储另一种类型的内存地址。C# 中的指针与 C 或 C++ 中的指针有相同的功能。
声明指针类型的语法:
type* identifier;
例如:
char* cptr;
int* iptr;
补充1:
关于装箱和拆箱
就像仓库,仓库里有货架,货架上有编号:A1,A2,A3...................., 这些编号就可以看做是引用类型,现在来了一批货,有 “土豆,黄瓜,西红柿”,这些就是值类型,如果你想让 A1=土豆,那么就要把土豆搬到 A1 里面去,这就叫装箱,装箱需要耗费人力和工时(也就是耗费CPU和内存),同理拆箱就要把对应编号的货物搬出来,也是需要耗费人力和工时。
装箱:值类型转换为对象类型, 实例:
int val = 8;
object obj = val;//整型数据转换为了对象类型(装箱)
拆箱:之前由值类型转换而来的对象类型再转回值类型, 实例:
int val = 8;
object obj = val;//先装箱
int nval = (int)obj;//再拆箱
只有装过箱的数据才能拆箱
补充2:
obj 和int之间关系
using System; namespace RectangleApplication { class ExecuteRectangle { static void Main(string[] args) { int a=; object obj; obj = a; obj =; Console.WriteLine("2: {0}", a); // 输出:2: 9 Console.WriteLine("1: {0}", obj); // 输出:1: 10 Console.ReadLine(); } } }
设置值 int a=9; obj=a; 当obj改变不会对 int a 进行改变,object 只是复制了 int a 的值出来然后对其操作而已。不会影响到 int 原来的值。
补充3:
C# 中 String 跟 string 的区别
string 是 C# 中的类,String 是 .net Framework 的类(在 C# IDE 中不会显示蓝色) C# string 映射为 .net Framework 的String 如果用 string, 编译器会把它编译成 String,所以如果直接用 String 就可以让编译器少做一点点工作。
如果使用 C#,建议使用 string,比较符合规范 string 始终代表 System.String(1.x) 或 ::System.String(2.0) ,String 只有在前面有 using System;的时候并且当前命名空间中没有名为 String 的类型(class、struct、delegate、enum)的时候才代表 System.String string 是关键字,String 不是,也就是说 string 不能作为类、结构、枚举、字段、变量、方法、属性的名称,而 String 可以。
String 是 CLR 的类型名称(也算是关键字),而 string 是 C# 中的关键字。string 在编译时候 C# 编译器会默认将其转换为 String,在这里会多增加几行转换的代码。很多时候都是建议使用 CLR 的类型而不要使用 C# 的类型(这是专家的建议)。比如说还有:使用 int 的时候最好使用 Int32 等。很多时候都是一个习惯问题,规范问题。还有一个不同就是在 VS 中表现的颜色不一样:String 是绿色,string 是蓝色。
补充4:
关于值类型、引用类型以及“栈”跟“堆”的关系
值类型,声明一个值类型的时候,是在“栈”中开辟一个内存空间来存放对应的值,当值类型的值发生改变的时候,则直接修改该内存空间所保存的值。例:
int n1 = ; int n2 = n1; Console.WriteLine(n1 + " "+ n2); // 5 5 n2 = ; Console.WriteLine(n1 + " " + n2) // 5 7
这里首先在“栈”中开辟一个内存空间用来保存 n1 的值 5,接着再在“栈”中开辟一个新的内存空间用来保存 n2 的值 5,所以显示出来的结果是 5 5。然后将 n2 在“栈”中对应的内存空间保存的值修改成 7,故显示出来的结果是 5 7。
引用类型,声明一个引用类型的时候,首先是在“堆”中开辟一个内存空间来存放对应的值,然后在“栈”中开辟一个内存空间用于保存在“堆”中开辟的内存空间的地址。当系统调用引用类型的时候,首先去“栈”中获取到地址,然后根据地址在“堆”中找到对应的内存空间来获取到对应值。像数组这样的引用类型
string[] a1 = new string[]{ "a" , "b" , "c" }; string[] a2 = a1; for(int i = ; i < a2.Length; i++) { Console.Write(a2[i] + " "); //a b c } a1[] = "d"; Console.WriteLine(); //换行 for(int i = ; i < a2.Length; i++) { Console.Write(a2[i] + " "); //a b d } Console.WriteLine();
这里首先是在“堆”中开辟一个内存空间(假设:0X55)用来保存数组a1的值,然后在“栈”中开辟一个内存空间(a1)用于保存地址 0X55。当将 a1 赋给 a2 时,是将地址赋给 a2,即在“栈”中开辟一个内存空间(a2)用于保存地址 0X55,所以输出 a2 的值是 a b c。当将 a1[2]修改成”d”的时候,修改的是“堆”中 0X55 内存空间保存的值,因为 a2 的地址和 a1 的地址一样,所以输出结果是 a b d。
而 string 是一个特殊的引用类型,先看下面代码:
string a = ""; string b = a; Console.WriteLine(a+" "+b); //123 123 string b = ""; Console.WriteLine(a+" "+b); //123 456
和数组类似的,这里首先在“堆”中开辟一个内存空间(假设:0X88)用来保存 a 的值 123,然后在“栈”中开辟一个内存空间(a)用于保存地址 0X88。
和数组不同的是,当将 a 赋给 b 的时候,首先是在“堆”中开辟一个新的内存空间(假设:0X101)用于保存值 123,然后在“栈”中开辟一个内存空间(b)用于保存地址 0X101,所以输出的结果是 123 123。
当修改 b 值时,并不是修改“堆”中 0X101 内存空间的值,而是在“堆”中重新开辟一个新的内存空间(假设:0X210)用于保存 b 修改后的值,然后将 b 在“栈”中对应的内存空间的所保存的地址修改成 0X210,所以输出的结果是 123 456。而“堆”中的 0X101 内存空间将在下次的垃圾回收中被回收利用。
C# 类型转换
类型转换从根本上说是类型铸造,或者说是把数据从一种类型转换为另一种类型。在 C# 中,类型铸造有两种形式:
- 隐式类型转换 - 这些转换是 C# 默认的以安全方式进行的转换, 不会导致数据丢失。例如,从小的整数类型转换为大的整数类型,从派生类转换为基类。
- 显式类型转换 - 显式类型转换,即强制类型转换。显式转换需要强制转换运算符,而且强制转换会造成数据丢失。
下面的实例显示了一个显式的类型转换:
实例
namespace TypeConversionApplication
{
class ExplicitConversion
{
static void Main(string[] args)
{
double d = 5673.74;
int i; // 强制转换 double 为 int
i = (int)d;
Console.WriteLine(i);
Console.ReadKey(); }
}
}
当上面的代码被编译和执行时,它会产生下列结果:
5673
C# 类型转换方法
C# 提供了下列内置的类型转换方法:
序号 |
方法 & 描述 |
1 |
ToBoolean |
2 |
ToByte |
3 |
ToChar |
4 |
ToDateTime |
5 |
ToDecimal |
6 |
ToDouble |
7 |
ToInt16 |
8 |
ToInt32 |
9 |
ToInt64 |
10 |
ToSbyte |
11 |
ToSingle |
12 |
ToString |
13 |
ToType |
14 |
ToUInt16 |
15 |
ToUInt32 |
16 |
ToUInt64 |
下面的实例把不同值的类型转换为字符串类型:
实例
namespace TypeConversionApplication
{
class StringConversion
{
static void Main(string[] args)
{
int i = ;
float f = 53.005f;
double d = 2345.7652;
bool b = true; Console.WriteLine(i.ToString());
Console.WriteLine(f.ToString());
Console.WriteLine(d.ToString());
Console.WriteLine(b.ToString());
Console.ReadKey(); }
}
}
当上面的代码被编译和执行时,它会产生下列结果:
75
53.005
2345.7652
True
补充1:
隐式转换和显式转换
隐式转换:C# 默认的以安全方式进行的转换。本质是从小存储容量数据类型自动转换为大存储容量数据类型,从派生类转换为基类。
实例:
namespace TypeConvertion { class Class1 { } class Class2 : Class1 //类Class2是类Class1的子类 { } class Program { static void Main(string[] args) { int inum = ; long lnum = inum; // 进行了隐式转换,将 int 型(数据范围小)数据转换为了 long 型(数据范围大)的数据 Class1 c1 = new Class2(); // 这里也是隐式转换,将一个新建的 Class2 实例转换为了其基类 Class1 类型的实例 C1 } } }
显式转换:通过用户使用预定义的函数显式完成的,显式转换需要强制转换运算符。
转换类型的范围大小和从属关系和隐式转换相反。显式转换可能会导致数据出错,或者转换失败,甚至无法编译成功。
实例:
double dnum = 100.1; int ifromd = (int)dnum; //double类型显式转换转为int类型 Class1 c11 = new Class1(); Class2 c22 = c11 as Class2; //使用as进行显式转换 Console.WriteLine(c22 is Class1); Console.WriteLine(c22 is Class2);
运行结果:
FALSE
FALSE
is操作符:检查对象是否与给定类型兼容。
as运算符:用于在兼容的引用类型之间执行转换。
as操作符类似于强制转换,但又有区别,当对象为null时,不会抛异常而是会返回null。
补充2:
类型之间的转换 - Convert 和 Parse
string locstr = 123.ToString();
//如果要将"locstr"转成整型数
//方法一: 用 Convert
int i = Convert.ToInt16(locstr);
//方法二: 用 Parse
int ii = int.Parse(locstr); int.TryParse(string s,out int i)
该方式也是将数字内容的字符串转换为int类型,但是该方式比int.Parse(string s) 好一些,它不会出现异常,最后一个参数result是输出值,如果转换成功则输出相应的值,转换失败则输出0。
class test { static void Main(string[] args) { string s1="abcd"; string s2=""; int a,b; bool bo1=int.TryParse(s1,out a); Console.WriteLine(s1+" "+bo1+" "+a); bool bo2=int.TryParse(s2,out b); Console.WriteLine(s2+" "+bo2+" "+b); } }
结果输出:
abcd False 0
1234 True 1234
补充3:
C# 中对 double 类型的数据取整,可以使用 convert.toint32() 方法,也可使用 int 强制转换为整数,使用 int 时并不存在四舍五入的情况,而是直接将后面的小数位数丢掉。比如:
class Program { static void Main(string[] args) { double a = 1.35; double b = 1.65; int a1 = Convert.ToInt32(a); int a2 = (int)(a); int b1 = Convert.ToInt32(b); int b2 = (int)(b); Console.WriteLine("{0}使用convert方法转化的结果为:{1}",a,a1); Console.WriteLine("{0}使用int强制转换的结果为:{1}",a,a2); Console.WriteLine("{0}使用convert方法转化的结果为:{1}", b, b1); Console.WriteLine("{0}使用int强制转换的结果为:{1}", b, b2); Console.ReadKey(); } }
程序运行结果如下:
1.35使用convert方法转化的结果为:1
1.35使用int强制转换的结果为:1
1.65使用convert方法转化的结果为:2
1.65使用int强制转换的结果为:1
补充4:
Convert.ToInt32() 与 int.Parse() 的区别
没搞清楚 Convert.ToInt32 和 int.Parse() 的细细微区别时千万别乱用,否则可能会产生无法预料的结果,举例来说:假如从 url 中取一个参数 page 的值,我们知道这个值是一个 int,所以即可以用 Convert.ToInt32(Request.QueryString["page"]),也可以用 int.Parse(Request.QueryString["page"]),但是如果 page 这个参数在 url 中不存在,那么前者将返回 0,0 可能是一个有效的值,所以你不知道 url 中原来根本就没有这个参数而继续进行下一下的处理,这就可能产生意想不到的效果,而用后一种办法的话没有 page 这个参数会抛出异常,我们可以捕获异常然后再做相应的处理,比如提示用户缺少参数,而不是把参数值当做 0 来处理。
(1) 这两个方法的最大不同是它们对 null 值的处理方法: Convert.ToInt32(null) 会返回 0 而不会产生任何异常,但 int.Parse(null) 则会产生异常。
(2) 对数据进行四舍五入时候的区别
- a. Convert.ToInt32(double value) 如果 value 为两个整数中间的数字,则返回二者中的偶数;即 3.5 转换为 4,4.5 转换为 4,而 5.5 转换为 6。不过 4.6 可以转换为 5,4.4 转换为 4 。
- b. int.Parse("4.5") 直接报错:"输入字符串的格式不正确"。
(3) 对被转换类型的区别 int.Parse 是转换 String 为 int, Convert.ToInt32 是转换继承自 Object 的对象为 int 的(可以有很多其它类型的数据)。你得到一个 object 对象, 你想把它转换为 int, 用 int.Parse 就不可以, 要用 Convert.ToInt32。
c#数据类型和类型转换的更多相关文章
- java与.net比较学习系列(3) 基本数据类型和类型转换
在Java中,数据类型分为两类,一类是基本数据类型,另外一类是引用类型. 而在C#中,数据类型分为三类,分别是基元类型,值类型和引用类型.其中基元类型是.net framework框架中预定义的类型, ...
- 【转】java与.net比较学习系列(3) 基本数据类型和类型转换
原文地址:https://www.cnblogs.com/mcgrady/p/3397874.html 阅读目录 一,整数类型 二,浮点数类型 三,字符类型 四,布尔类型 五,类型转换之自动转换 六, ...
- 大数据学习--day02(标识符、变量、数据类型、类型转换、进制转换、原码反码补码)
标识符.变量.数据类型.类型转换.进制转换.原码反码补码 标识符: java50个关键字不能做标识符,以数字开头不能做标识符(这个老是忘记写一个类名的时候) 变量: 变量分为成员变量和局部变量,注意作 ...
- python入门4 python查看数据类型及类型转换
查看数据类型:type() 类型转换:int(),float(),char(),ord(),str(),bool() #coding:utf-8 #/usr/bin/python "&quo ...
- 【Python系统学习02】数据类型与类型转换
一.数据类型 字符串 整数 浮点数 [补充中...] 1.字符串 str 字符串:英文string,简写str. name = '小石头:' print(name,'2019', '12', '24' ...
- 2 JavaScript输出&字面量&变量&操作符&语句&标识符和关键字&字符集&语句&数据类型与类型转换
JS输出: JavaScript没有任何打印或者输出的函数,但是可以用不同的方式输出数据 window.alert():弹出警告框 document.write():写入文档 innerHTML:写入 ...
- 02-JS中的数据类型及类型转换
02-JS中的数据类型及类型转换 一.数据类型 JS中的值,无论是字面量还是变量,都有明确的类型. (一)概述 1.基本类型5种 number 数字类型 string 字符串类型 boolean 布尔 ...
- SSIS 数据类型和类型转换
在进行ETL开发时,数据类型(Data Type)是最基础的,但也容易被忽略,楼主使用的SQL Server 版本是2012,用此博文记录,常用的SSIS数据类型和TSQL数据类型的映射.SSIS的数 ...
- 数据类型/强制类型转换 和运算符---标识符规则/关键字 a++和++a区别
3.2关键字都是小写,TRUE FALSE NULL都不是Java关键字 3.3数据类型 变量相当于一个有名称的容器,该容器用于装各种不同类型的数据 Java类型分为2种 基本类型: 引用类型: 基本 ...
- .net学习之.net和C#关系、运行过程、数据类型、类型转换、值类型和引用类型、数组以及方法参数等
1..net 和 C# 的关系.net 是一个平台,C#是种语言,C#语言可以通过.net平台来编写.部署.运行.net应用程序,C#通过.net平台开发.net应用程序2..net平台的重要组成FC ...
随机推荐
- apk程序查找方法调用
有android killer,现在ida对android的支持等一些方便工具,此篇(关于搜索和修改代码)废弃. 没有好的调试工具下 常用插代码(如果怕影响寄存器值,可以将.locals xxx改多几 ...
- Leetcode(58)题解:Length of Last Word
https://leetcode.com/problems/length-of-last-word/ 题目: Given a string s consists of upper/lower-case ...
- ivy
ivy https://ant.apache.org/ivy/ Apache Ivy™ is a popular dependency manager focusing on flexibility ...
- [TJOI2017] 不勤劳的图书管理员
题目描述 加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员.他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让小豆产生这两本书页数的和的厌烦度.现在有n本被打乱顺序的书, ...
- oracle中的exists和not exists和in用法详解
in 是把外表和内表作hash 连接,而exists是对外表作loop循环,每次loop循环再对内表进行查询. not exists:做NL,对子查询先查,有个虚表,有确定值,所以就算子查询有NULL ...
- bzoj5328: [Sdoi2018]物理实验
果然我还是太菜了,爆了一天才过....隔壁肉丝都不知道喊了多少句哎╮(╯▽╰)╭我又A了什么傻逼题(然鹅就是wf和国集的题QWQ) 其实这个题就是个裸题,但是我就是不会... 这个题第一步就是明显的旋 ...
- nodejs api 中文文档
文档首页 英文版文档 本作品采用知识共享署名-非商业性使用 3.0 未本地化版本许可协议进行许可. Node.js v0.10.18 手册 & 文档 索引 | 在单一页面中浏览 | JSON格 ...
- html5--6-4 CSS选择器
html5--6-4 CSS选择器 实例 学习要点 掌握常用的CSS选择器 了解不太常用的CSS选择器 什么是选择器 当我们定义一条样式时候,这条样式会作用于网页当中的某些元素,所谓选择器就是样式作用 ...
- 【转载】浅谈Excel开发:一 Excel 开发概述
博客园就是好,想要什么都给总结了,多谢 原文转载:http://www.cnblogs.com/yangecnu/p/Excel-Develpment-Introduction.html 做Offic ...
- Codeforces-914F Substrings in a String (Bitset求T串中S串出现次数)
之前有过区域赛,简化版问题: 给定一个小写字符组成的字符串S,(|S|<1e5,下标从1开始),现在有Q种操作,对于每个操作Q(Q<=1e5),输入opt, 如果opt==1,输入x,c, ...