类比python学C#(2)数据类型

类比python学C#(2)数据类型

  • 数据类型
    • 值类型
            • 关于值类型、引用类型以及“栈”跟“堆”的关系
            • 值类型与引用类型的区别
    • 引用类型
        • 对象(Object)类型
            • 关于装箱和拆箱
        • 动态(Dynamic)类型
        • 字符串(String)类型
    • 指针类型
  • 类型转换
        • 隐式类型转换 (小转大)
        • 显式类型转换(大转小)
            • 隐式转换和显式转换
            • Convert.ToInt32() 与 int.Parse() 的区别
  • 变量的申明和初始化
  • 运算符
          • 可空类型修饰符 ?
          • 三元(运算符)表达式 ?:
          • 空合并运算符 ??
          • NULL 检查运算符 ?.
        • 优先级
        • i++ 和++i的区别

数据类型

值类型

值类型直接包含数据。比如 int、char、float,它们分别存储数字、字符、浮点数。当您声明一个 int 类型时,系统分配内存来存储值。

下表列出了 C# 2010 中可用的值类型:
类比python学C#(2)数据类型_第1张图片

关于值类型、引用类型以及“栈”跟“堆”的关系

值类型,声明一个值类型的时候,是在“栈”中开辟一个内存空间来存放对应的值,当值类型的值发生改变的时候,则直接修改该内存空间所保存的值

引用类型,声明一个引用类型的时候,首先是在“堆”中开辟一个内存空间来存放对应的值,然后在“栈”中开辟一个内存空间用于保存在“堆”中开辟的内存空间的地址。当系统调用引用类型的时候,首先去“栈”中获取到地址,然后根据地址在“堆”中找到对应的内存空间来获取到对应值。像数组这样的引用类型

值类型与引用类型的区别

从内存上看,值类型是在栈中的操作,而引用类型是在堆中的操作。(导致 => 值类型存取速度快,引用类型存取速度慢。)


从本质上看,值类型表示实际数据,引用类型表示指向存储在内存堆中的数据的指针或引用。(值类型是具体的那个数值所占用的空间大小,而引用类型是存放那个数值的空间地址。)


从来源上看,值类型继承自System.ValueType,引用类型继承自System.Object。

特别的:结构体是值类型,类和string是引用类型。


当一个值类型转换为对象类型时,则被称为 装箱;另一方面,当一个对象类型转换为值类型时,则被称为 拆箱。

动态类型与对象类型相似,但是对象类型变量的类型检查是在编译时发生的,而动态类型变量的类型检查是在运行时发生的。

引用类型

对象(Object)类型

对象(Object)类型 是 C# 通用类型系统(Common Type System - CTS)中所有数据类型的终极基类。Object 是 System.Object 类的别名。所以对象(Object)类型可以被分配任何其他类型(值类型、引用类型、预定义类型或用户自定义类型)的值。但是,在分配值之前,需要先进行类型转换。

当一个值类型转换为对象类型时,则被称为 装箱;另一方面,当一个对象类型转换为值类型时,则被称为 拆箱。

关于装箱和拆箱
 装箱:值类型转换为对象类型, 实例:

int val = 8;
object obj = val;//整型数据转换为了对象类型(装箱)

拆箱:之前由值类型转换而来的对象类型再转回值类型, 实例:

int val = 8;
object obj = val;//先装箱
int nval =int)obj;//再拆箱

只有装过箱的数据才能拆箱

就像仓库,仓库里有货架,货架上有编号:A1,A2,A3…, 这些编号就可以看做是引用类型,现在来了一批货,有 “土豆,黄瓜,西红柿”,这些就是值类型,如果你想让 A1=土豆,那么就要把土豆搬到 A1 里面去,这就叫装箱,装箱需要耗费人力和工时(也就是耗费CPU和内存),同理拆箱就要把对应编号的货物搬出来,也是需要耗费人力和工时。

动态(Dynamic)类型

您可以存储任何类型的值在动态数据类型变量中。这些变量的类型检查是在运行时发生的。
声明动态类型的语法:

dynamic <variable_name> = value;

例如:

dynamic d = 20;

动态类型与对象类型相似,但是对象类型变量的类型检查是在编译时发生的,而动态类型变量的类型检查是在运行时发生的。

字符串(String)类型

字符串(String)类型 允许您给变量分配任何字符串值。字符串(String)类型是 System.String 类的别名。它是从对象(Object)类型派生的。字符串(String)类型的值可以通过两种形式进行分配:引号和 @引号。
@引号---->有点类似于Python中的 ----> r引号

例如:

String str = "runoob.com";

一个 @引号字符串:

@"runoob.com";

C# string 字符串的前面可以加 @(称作"逐字字符串")将转义字符(\)当作普通字符对待,比如:

string str = @"C:\Windows";

等价于:

string str = "C:\\Windows";

@ 字符串中可以任意换行,换行符及缩进空格都计算在字符串长度之内。

string str = @"";

指针类型

指针类型变量存储另一种类型的内存地址。C# 中的指针与 C 或 C++ 中的指针有相同的功能。

声明指针类型的语法:

type* identifier;

例如:

char* cptr;
int* iptr;

类型转换

类型转换从根本上说是类型铸造,或者说是把数据从一种类型转换为另一种类型。在 C# 中,类型铸造有两种形式:

隐式类型转换 (小转大)
  • 这些转换是 C# 默认的以安全方式进行的转换, 不会导致数据丢失。例如,从小的整数类型转换为大的整数类型,从派生类转换为基类。
显式类型转换(大转小)
  • 显式类型转换,即强制类型转换。显式转换需要强制转换运算符,而且强制转换会造成数据丢失。
 double d = 5673.74;
 int i;

 // 强制转换 double 为 int
 i = (int)d;


python中的写法是:

i = int(d)

C# 提供了下列内置的类型转换方法:
类比python学C#(2)数据类型_第2张图片

类比python学C#(2)数据类型_第3张图片

隐式转换和显式转换

隐式转换:C# 默认的以安全方式进行的转换。本质是从小存储容量数据类型自动转换为大存储容量数据类型,从派生类转换为基类。

显式转换:通过用户使用预定义的函数显式完成的,显式转换需要强制转换运算符。转换类型的范围大小和从属关系和隐式转换相反。显式转换可能会导致数据出错,或者转换失败,甚至无法编译成功。

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") 直接报错:"输入字符串的格式不正确"。
c. int(4.6) = 4 Int 转化其他数值类型为 Int 时没有四舍五入,强制转换。

(3) 对被转换类型的区别 int.Parse 是转换 String 为 int, Convert.ToInt32 是转换继承自 Object 的对象为 int 的(可以有很多其它类型的数据)。你得到一个 object 对象, 你想把它转换为 int, 用 int.Parse 就不可以, 要用 Convert.ToInt32。

变量的申明和初始化

C#

1int i, j, k;
char c, ch;
float f, salary;
double d;2---->数组

double[] balance;
初始化数组
	double[] balance = new double[10];
赋值给数组
	double[] balance = new double[10];
	balance[0] = 4500.0;
	
	您可以在声明数组的同时给数组赋值,比如:
	
	double[] balance = { 2340.0, 4523.69, 3421.0};
	
	您也可以创建并初始化一个数组,比如:
	
	int [] marks = new int[5]  { 99,  98, 92, 97, 95};
	
	在上述情况下,你也可以省略数组的大小,比如:
	
	int [] marks = new int[]  { 99,  98, 92, 97, 95};
	
	您也可以赋值一个数组变量到另一个目标数组变量中。在这种情况下,目标和源会指向相同的内存位置:
	
	int [] marks = new int[]  { 99,  98, 92, 97, 95};
	int[] score = marks;
二维数组
	C#中,我们在创建二维数组的时候,一般使用arr[][]的形式,例如
	
	int[][] aInt = new int[2][];
	
	但声明二维数组还有一种方法,是使用arr[,]的形式。两者有什么区别呢?
	
	
	实际上,形如arr[,]只能声明等长的二维数组,例如
	
	int[,] ab1 = new int [2,3];//默认值为0; int[,] ab2 = new int[2,3]{{1,2,3},{4,5,6}};
	
	
	形如arr[][]的形式则可以声明等长二维数组,也可以声明不等长二维数组。例如
	
	int [][] abc = new int[2][]; abc[0] = new int[]{1,2}; abc[1] = new int[]{3,4,5,6};






python

1:
n=1
b=2
s= 'lalala'2:
list01 = []
list02 = [1,2,3,4,5,6]
list03 = [i for i in range(18)]
list04 = list('abcd')
二维数组 例如3X3数组
list05 = [
[1,2,3],
[4,5,6],
[7,8,9],
]3:
dict01 = {}
dict02 = {'name':'Amy','age':18}

运算符

算数运算符 + - * /、%、 ++、 - -
关系运算符 < 、> 、<=、>=、==、!=
逻辑运算符 && 与、||或、!非
位运算符 &与、|或、^非、~取反、<<左移、>>右移
赋值运算符 += 、-= 、*=、/=、%=、&=按位与、|=按位或、^=按位非、<<=按位左移、>>=按位右移
其他运算符 &取地址、*指针、? :条件表达式、is、as、sizeof()、typeof()

?:
条件表达式

例如:
x?y:z 表示如果表达式 x 为 true,则返回 y;如果 x 为 false,则返回 z,
是 if{}else{} 的简单形式。

as
强制转换,即使转换失败也不会抛出异常。

Object obj = new StringReader("Hello");
StringReader r = obj as StringReader; 
可空类型修饰符 ?

引用类型可以使用空引用表示一个不存在的值,而值类型通常不能表示为空。

例如:string str=null; 是正确的,int i=null; 编译器就会报错。

为了使值类型也可为空,就可以使用可空类型,即用可空类型修饰符 ? 来表示,表现形式为 T? 。

例如:int? 表示可空的整形,DateTime? 表示可为空的时间。

T? 其实是 System.Nullable(泛型结构)的缩写形式,也就意味着当你用到 T?时编译器编译时会把T?编译成 System.Nullable 的形式。

例如:int?,编译后便是 System.Nullable 的形式。
三元(运算符)表达式 ?:
例如:x?y:z 表示如果表达式 x 为 true,则返回 y;如果 x 为 false,则返回 z,
是 if{}else{} 的简单形式。
空合并运算符 ??

用于定义可空类型和引用类型的默认值。

如果此运算符的左操作数不为 null,则此运算符将返回左操作数,否则返回右操作数。

例如:a??b 当 a 为 null 时则返回 b,a 不为 null 时则返回 a 本身。

空合并运算符为右结合运算符,即操作时从右向左进行组合的。

如: a??b??c 的形式按 a??(b??c) 计算。

NULL 检查运算符 ?.
int? firstX = points?.FirstOrDefault()?.X;

从这个例子中我们也可以看出它的基本用法:如果对象为 NULL,则不进行后面的获取成员的运算,直接返回 NULL。

需要注意的是,由于 ?. 运算符返回的可以是 NULL,当返回的成员类型是 struct 类型的时候, ?. 和 . 运算符的返回值类型是不一样的。

Point p = new Point(3, 2); 
Console.WriteLine(p.X.GetType() == typeof(int));        //true
Console.WriteLine(p?.X.GetType() == typeof(int?));      //true
优先级

类比python学C#(2)数据类型_第4张图片

i++ 和++i的区别
1:

c = a++: 先将 a 赋值给 c,再对 a 进行自增运算。
c = ++a: 先将 a 进行自增运算,再将 a 赋值给 c 。

你可能感兴趣的:(c#)