`
isiqi
  • 浏览: 16356658 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

.net 基础知识大杂烩(1) ——内建类型

阅读更多
我们在思想、言词、行为方面的精确性程度是对我们是否忠于真理的初步检验。
——巴兰德

摘要

许多公司在面试的时候都喜欢问一些非常基础的问题。例如面试官会问:“.net里有哪些内建类型?”,应聘者一边心里嘀咕着:“就不能整点4岁滴?”,一边回答说:“有int、long、double、decimal....喔,对了,还有String,常用的差不多就是这些了。”这个答案并没有错,但是它很难让你脱颖而出。在这个什么都讲优化的年代,我们也有必要做一点“面试优化”了^_^

内建类型

.Net Framework 类型 位数 范围 C# VB
类型 示例 类型 示例
类型 示例 类型 示例
Boolean 1 / bool bool a; // 编译错误:a 未必初始化就不能使用(对于所有基本类型都有这个约束,后面就不一一列举了)
bool b = true;
Boolean Dim a As Boolean' OK. a = False (对于所有基本类型都会像这样被初始化为默认值,后面就不一一列举了)
Dim b As Boolean = True
SByte 1 -2^7 ~ 2^7-1 sbyte sbyte a = -3;
a = 128; // 编译错误:常量值“128”无法转换为“sbyte”
SByte Dim a As SByte = -3
a = 128 ' 编译错误:常量表达式无法在类型“SByte”中表示。
Byte 1 0 ~ 2^8-1 byte byte a = 128;
a = -3; // 编译错误:常量值“-3”无法转换为“byte”
Byte Dim a As Byte = 128
a = -3 ' 编译错误:常量表达式无法在类型“Byte”中表示。
Int16 2 -2^15 ~ 2^15-1 short short a = -3;
a = 32768; // 编译错误:常量值“32768”无法转换为“short”
Short Dim a As Short = -3
a = 32768 ' 编译错误:常量表达式无法在类型“Short”中表示。
UInt16 2 0 ~ 2^16-1 ushort ushort a = -3; // 编译错误:常量值“-3”无法转换为“ushort”
a = 32768;
UShort Dim a As UShort = -3 ' 编译错误:常量表达式无法在类型“UShort”中表示。
a = 32768
Int32 4 -2^31 ~ 2^31-1 int int a = -3; Integer Dim a As Integer = -3
UInt32 4 0 ~ 2^32-1 uint uint a = 0; UInteger Dim a As UInteger = 0
Int64 8 -2^63 ~ 2^63-1 long long a = 3;
long b = 3L;
Long Dim a as Long = 3
Dim a as Long = 3L
UInt64 8 0 ~ 2^64-1 ulong ulong a = 3;
ulong b = 3L;
ULong Dim a as ULong = 3
Dim a as ULong = 3L
Single 4 ±1.5*10^-45 ~ ±3.4*10^38
有效数字7位
float float a = 21; // OK. a = 21
float b = 21.5; // 编译错误:不带后缀的小数被视为double类型。
float c = 21.5F; // c = 21.5
float t = 12345678L; // OK, t = 12345680.0。int 和 long 可被隐式转换为float, 但精度会有损失
Single Dim a As Single = 21 ' OK
Din b As Single = 21.5 'OK. VB的编译器能根据b的类型自行确定21.5的类型
Dim c As Single = 21.5F 'OK
Dim t As Single = 12345678L; ' OK, t = 12345680.0。int 和 long 可被隐式转换为float, 但精度会有损失
Double 8 ±5.0*10^−324 ~ ±1.7*10^308
有效数字15~16位
double double a = 21.2; // a = 21.2
double b = 21.2F; // b = 21.2000007629395
double c = 34.6 - 34.0; // c = 0.600000000000001
double d = 21; // d = 21
Double Dim a As Double = 21.2 ' a = 21.2
Dim b As Double = 21.2F ' b = 21.2000007629395
Dim c As Double = 34.6 - 34.0 ' c = 0.600000000000001
Dim d As Double = 21 ' d = 21
Decimal 16 ±1.0×10^−28 ~ ±7.9*10^28
有效数字28~29位
deicmal decimal a = 21L; // a = 21
decimal b = 21;// b = 21
decimal c = 1.5; // 编译错误:不能隐式地将 Double 类型转换为“decimal”类型
decimal d = 1.5M; // d = 1.5
Decimal Dim a As Decimal = 21L ' a = 21
Dim b As Decimal = 21 ' b = 21
Dim c As Decimal = 1.5 ' OK VB的编译器能根据c的类型自行确定1.5的类型
Dim d As Decimal = 1.5D ' 注意在VB里“D”表示“Decimal”;而在C# 里“D”表示“Double”
Char 2 0 ~ 2^16-1 char char c1 = 'a';
char c2 = '天';
int a = (int)c1; // a = 97
int b = (int)c2; // b = 22825 (0x5929)
char c3 = '\u5929'; // c3 = '天'
char c4 = '\x5929'; // c4 = '天'
Char Dim c1 As Char = "a"
Dim c2 As Char = "天"
Dim a As Integer = AscW(c1)' a = 97
Dim b As Integer = AscW(c2)' b = 22825 (0x5929)
Dim c3 As Char = ChrW(22825) ' c3 = "天"
Dim c4 As Char = ChrW(&H5929) ' c4 = "天"
String / / string string a = "abc";
string b = "123";
string c = a + b; // c = "abc123"
string t = null;
String Dim a As String = "abc"
Dim b As String = "123"
Dim c As String = a + b ' c = "abc123"
Dim d As String = a & b ' d = "abc123"
Din t as String = Nothing
Object / / object Object a = 9; // 装箱
int b = (int)a; // 拆箱
Dim a As Object = 9 ' 装箱
Dim b As Integer = a ' 拆箱

出彩

1. float、double、decimal之间有什么异同?

float和double是符合IEEE标准的二进制浮点数,它们的取值范围比decimal大得多,但是有效数字位数比decimal少,有舍入误差,只有符合“k/(2^n) 其中k和n均为整数”的数值能够被精确表示,其它形式的数值均有舍入误差。
例如下列数值不会产生舍入误差
doublea=0.5//a=(1/2^1)被实际存储为0.5
doubleb=0.25;//a=(1/2^2)被实际存储为0.25
doublec=0.1875;//a=(3/2^4)被实际存储为0.1875
doubled=13.28125;//a=(425/2^5)被实际存储为13.28125

而下列数值则会产生舍入误差
doublee=0.2;//a=(1/5)被实际存储为0.20000000000000001
doublef=0.3;//a=(3/10)被实际存储为0.29999999999999999
doubleg=0.6;//a=(3/5)被实际存储为0.59999999999999998
doubleh=34.6;//a=(173/5)被实际存储为34.600000000000001


decimal 是专为金融和财务设计的十进制浮点数,它的取值范围没有float和Decimal那么大(但是对于财务计算足够了),但是有效数字比double多,没有舍入误差,所以对于金额等对精度要求高的数据应该使用decimal。

需要注意的是Decimal是一个非常特殊的类型。虽然C#和VB都把Decimal看作是一个primitive type,但CLR却不是这样。这意味着:
①操作Decimal值得执行效率将比其它primitive type低。请看下面的示例:


比较float和decimal这两种不同的类型所对应的IL代码,可以发现两个double类型的数字相减是使用的sub指令,而两个decimal类型的数字相减需要调用Decimal的operator-()函数。

②checked和unchecked操作符,以及相关的编译器命令行开关对Decimal没有任何影响。因为checked操作符指示编译器使用add.ovf、conv.ovf等进行溢出检查的指令;unchecked操作符指示编译器使用add、conv等不进行溢出检查的指令。由于这些指令只对primitive type有效,所以不管是否使用了unchecked操作符,只要发生溢出Decimal都会抛出异常。





2. 什么是装箱和拆箱?如何避免?

1) 装箱。装箱的核心是把值类型转换为对象类型,或者转换为由值类型执行的接口类型。常见的装箱转换有4种:

① 从任何值类型转换为对象类型。
举例:
int i = 28;
object age =i; // 装箱
问题是真会有人写这么BT的代码么?有的。因为在.net里值类型是不能被赋值为null的。例如
int i = null; // 编译错误:无法将 NULL 转换成“int”,因为它是一种值类型
那么该如何表示数据库中的null值呢?方法之一就是像上面那样用一个object来表示数据库中的一个字段。只是这种方法不仅会造成装箱,而且可读性也不好,因为我们只能通过注释和文档才能知道age里面保存的什么类型的数据。

解决方法1(适用于.net 1.x):
可以约定一个“哨兵值”,例如约定int.MaxValue表示null:
public static bool IsNull(int arg)
{
return arg == int.MaxValue;
}

解决方法2(适用于.net 2.0):
在.net 2.0中新增了可空值类型 Nullable<T> ,可以很好地解决这个问题。
Nullable<int> age = null; // 这是个语法糖,相当于 Nullable<int> age = new Nullable<int>();
// 也可以使用C#提供的简便写法: int? age = null;
bool b = age.HashValue; // b =false
age = 9; // 这是个语法糖,相当于 age = new Nullable<int>(9);
int i = age ?? 28; // 相当于 int i = age.HasValue ?age.GetValueOrDefault() : 28;
可以看出通过C#提供的一些语法糖,使代码看上去像是把null赋值给了age,其实不过是使用默认值初始化了age而已,而age的bool型的属性HashValue默认会被初始化为false,这样就正好可以表示age是“null”这一语义了。整个过程都没有发生装箱。

再举一个装箱的例子:
int age = 17;
Console.WriteLine(age); // 没有发生装箱操作,因为Console有一个WriteLine(Int32)的函数定义。
Console.WriteLine("{0}", age); // 装箱。因为符合这个调用的函数只有Console.WriteLine(String, Object);
// 所以相当于调用 Console.WriteLine("{0}", (Object)age)
// 这是一个很隐蔽“将值类型转换为对象类型”的操作
解决方法是:
Console.WriteLine("{0}", age.ToString()); // 没有发生装箱操作
之所以没有发生装箱是因为String本身就是一个引用类型(后面会讲到),自然不会发生装箱了。不过在Console.WriteLine() 函数内部还是会再调用一次 arg.ToString(),所以Console.WriteLine("{0}", age.ToString())和Console.WriteLine("{0}", age)哪个更快取决于“把arg装箱”更快还是调用“arg.ToString() ”更快。我实测的结果是Console.WriteLine("{0}", age)稍微快一点,不信你也可以测试一下。
<t></t>
② 从任何值类型转换为System.ValueType类型。
举例:
int a = 9;
ValueType b = a; // 装箱

③ 从任何值类型转换为值类型实现的任何接口类型。
举例:
decimal a = 9;
IConvertible b = a;// 装箱
int c = b.ToInt32(null);
decimal等数值类型实现了IFormattable, IComparable, IConvertible等等很有用的接口,可是TNND对这些接口全部采用了显示接口实现,结果就是这些有用的函数不能直接调用,必须先转换成对应的接口才行。

④ 从枚举类型转换为System.Enum类型。
enum Tricolor { Red, Green, Blue }

Tricolor a = Tricolor.Blue;
Enum b = a; // 装箱

2) 拆箱。拆箱相对于装箱是一个相反的过程,其核心是将引用类型显示转换为值类型,或者是将一个接口类型转换为一个实现该接口的值类型。
① 从对象类型转换为任何值类型。
举例:
int a = 9;
object b = a; // 装箱
int c = (int)b; // 拆箱

② 从System.ValueType类型转换为任何值类型。
③ 从任何接口类型转换为实现该接口类型的任何值类型。
④ 从System.Enum类型转换为任何枚举类型。
enum Tricolor { Red, Green, Blue }

Tricolor a = Tricolor.Blue;
Enum b = a; // 装箱
Tricolor c = (Tricolor)b; // 拆箱
Tricolor red = (Tricolor)Enum.Parse(typeof(Tricolor), "Red"); // 拆箱, 因为Enum.Parse()返回值是Object类型

3. String到底是引用类型还是值类型?

String是引用类型,但是它(被故意设计成)具有值类型的行为。换句话说,人们希望String具有值类型的行为,但是出于性能的考虑需要它是引用类型。
例如
string a = "对1-2-3的赞美之词(此处省略2000字...)"; // a 将占用约4k内存
string b = a; // 如果 String 是值类型,就必须进行由 a 到 b 的逐位拷贝,
// 那么a和b加起来将占用约8K内存,且效率不佳。
// 如果String是引用类型,那么b就是一个指向a的引用,b只需要4个字节的内存。
stringb = b.Insert(1, "傻瓜"); // 我们想把 "傻瓜" 插入到b中,可是因为b是a的引用,修改b就相当
// 于修改了a,而我们不喜欢这样(也就是说我们希望String具有值类
// 型的行为)。于是Insert()函数被设计成并不直接修改b,而是先把
// b克隆一份,然后修改这个克隆,然后返回这个克隆。这就是
// ValueObject 模式
Console.WriteLine(a); // 输出 "对1-2-3的赞美之词(此处省略2000字...)";
Console.WriteLine(b); // 输出 "对傻瓜1-2-3的赞美之词(此处省略2000字...)";


http://www.cnblogs.com/1-2-3/archive/2008/01/26/net-basic-knowledge-1-cs-vb-native-type.html

分享到:
评论

相关推荐

    亮剑.NET深入体验与实战精要.part2

     第3章 asp.net开发大杂烩  3.1 页面生命周期  3.2 页面状态管理  ……  第4章 windows窗体编程你也行  第5章 数据库开发  第6章 关于xml  第7章 web service开发详解  第8章 用户体验的杀手锏——...

    亮剑.NET深入体验与实战精要2

    第3章 ASP.NET开发大杂烩 113 3.1 页面生命周期 114 3.1.1 独立页面生命周期事件顺序 114 3.1.2 具有Master页的生命周期事件顺序 116 3.1.3 ASP.NET生命周期详解 118 3.2 页面状态管理 120 3.2.1 Cookie 121 3.2.2...

    基础传统神经网络算法大杂烩.zip

    基础传统神经网络算法大杂烩基础传统神经网络算法大杂烩 基础传统神经网络算法大杂烩基础传统神经网络算法大杂烩 基础传统神经网络算法大杂烩基础传统神经网络算法大杂烩 基础传统神经网络算法大杂烩基础传统神经...

    GenomeDotNet:.NET项目的大杂烩,可用于处理23andme数据

    .NET项目的大杂烩,可用于处理23andme数据 ISOGG 2015 Y-DNA单倍体树 在互联网上寻找易于解析的ISOGG 2015 Y-DNA Haplogroup树的版本,我倒霉了。 因此,我决定刮除ISOGG的页面并将数据投影到易于使用的JSON文件中。...

    亮剑.NET深入体验与实战精要3

    第3章 ASP.NET开发大杂烩 113 3.1 页面生命周期 114 3.1.1 独立页面生命周期事件顺序 114 3.1.2 具有Master页的生命周期事件顺序 116 3.1.3 ASP.NET生命周期详解 118 3.2 页面状态管理 120 3.2.1 Cookie 121 3.2.2...

    亮剑.NET深入体验与实战精要.part1.

     第3章 asp.net开发大杂烩  3.1 页面生命周期  3.2 页面状态管理  ……  第4章 windows窗体编程你也行  第5章 数据库开发  第6章 关于xml  第7章 web service开发详解  第8章 用户体验的杀手锏——...

    ASP.NET 大杂桧

    在"ASP.NET 大杂烩"这个主题中,我们主要关注三个核心知识点:AJAXPro的参数传递、ASP.NET分页技术和Repeater控件。 首先,AJAXPro是ASP.NET中的一个库,它允许开发者创建高效的、具有部分页面更新功能的Web应用,...

    亮剑.NET深入体验与实战精要.part3

     第3章 asp.net开发大杂烩  3.1 页面生命周期  3.2 页面状态管理  ……  第4章 windows窗体编程你也行  第5章 数据库开发  第6章 关于xml  第7章 web service开发详解  第8章 用户体验的杀手锏——...

    亮剑.NET深入体验与实战精要.part4(完)

     第3章 asp.net开发大杂烩  3.1 页面生命周期  3.2 页面状态管理  ……  第4章 windows窗体编程你也行  第5章 数据库开发  第6章 关于xml  第7章 web service开发详解  第8章 用户体验的杀手锏——...

    tomcat漏洞大杂烩1

    【标题】:“Tomcat漏洞大杂烩1” 【描述】:描述中提到的是一些关于Tomcat服务器的安全问题,特别是Windows环境下的一些限制以及NTFS流的特性。在Windows系统下,文件名不允许以空格结尾,这是一个操作系统级别的...

    各种工具大杂烩

    在IT行业中,"工具大杂烩"通常指的是包含多种不同类型工具的集合,这些工具可能涵盖了开发、测试、运维、数据分析等多个领域。在这个压缩包文件"聚宝盆"中,我们可以推测它可能包含了丰富的IT资源,旨在帮助用户一站...

    大杂烩proteus仿真MCS51一百例

    大杂烩proteus仿真MCS51一百例; 有100个例题学习1!

    C++基础入门教程(一):基础知识大杂烩

    注意:本系列教程不适合无任何编程语言基础的朋友,只是作为C++基础的一种补充。 教程内容基于《C++ Primer Plus》一书,适合初学者,熟手请直接忽略。 1. 如果你不注释,那么,我会把你注释掉~! C++的注释有2种, ...

    (大杂烩)proteus仿真MCS51一百例.rar

    (大杂烩)proteus仿真MCS51一百例.rar(大杂烩)proteus仿真MCS51一百例.rar(大杂烩)proteus仿真MCS51一百例.rar(大杂烩)proteus仿真MCS51一百例.rar(大杂烩)proteus仿真MCS51一百例.rar(大杂烩)proteus仿真MCS51一百例...

    人脸识别大杂烩

    总的来说,“人脸识别大杂烩”涵盖的内容广泛且深入,从基础理论到前沿技术,从算法实现到实际应用,无不体现了这一领域的发展活力和广阔前景。通过不断的研究和创新,人脸识别技术将持续推动社会智能化的步伐。

    科研论文作图之大杂烩图片的制作.rar

    视频教程"科研论文作图010_大杂烩图片的制作.wmv"则可能是对这些理论知识的实际操作演示,通过动态的方式展示制作过程,使学习者能够更直观地掌握技巧。这可能包括一步步的指导,例如如何合并不同的图表元素,调整...

    网络安全大杂烩

    罗列了一些网络安全方面的知识,简单介绍了安全测试的知识。

    测试大杂烩

    在这个“测试大杂烩”中,我们将会探讨软件测试的基础概念、测试用例设计、自动化测试的原理以及在实际项目中如何有效地运用这些知识。 首先,我们要理解什么是软件测试。它是一种系统性的过程,用于评估软件产品...

Global site tag (gtag.js) - Google Analytics