解读经典《C#高级编程》第七版 Page79-93.对象和类型.Chapter3
前言
本篇我们继续讲解本章其余的部分:构造函数、只读字段、匿名类型、结构详解、部分类、静态类、Object类、扩展方法,等。
01
类
构造函数
构造函数是一种特殊的方法:
- 与类同名
- 没有返回值,甚至不能写void(但可以写修饰符public,private,protected)
- 未指定构造函数时,编译器会自动创建默认构造函数;一旦手工创建了构造函数,编译器就不会再创建默认构造函数
- 构造函数可重载,同方法一样
- 静态构造函数:构造函数加static关键字;它只执行一次,一般用于初始化静态字段或者属性;静态构造函数执行时机并不确定,因此有顺序依赖的代码不要写在静态构造函数中(比如一个程序集中有10个静态构造函数,哪个先执行并无定数,我简单测试的结果是:在访问类的静态字段/属性时,静态构造函数会被执行),其中的代码逻辑尽量保持简单和单一;静态构造函数无访问修饰符、无参数,因为没有意义;静态构造函数只能访问静态成员,不能访问实例成员
- 构造函数的相互调用
当我们把构造函数看成方法后,构造方法间的互调用,我们可能会认为和方法一样,比如:
TestMain(){
}
TestMain(int arg){
this(); //构造方法互调用
int a = 10;
}
但实际上,这种方法只适用于Java(且构造方法的调用必须在首行)。在.Net中,使用的是叫做“构造函数初始化器”的语法:
Test()
: base() //调用基类的初始化器
{
}
Test(int arg)
:this(arg, 5) //初始化器
{
arg = 10;
}
Test(int arg1, int arg2)
:this() //初始化器
{
}
构造函数初始化器在构造函数函数体执行之前执行。this为类的多个构造函数的互调用,base为对基类的构造函数的调用。
只读字段
只读字段(readonly)是对常量的补充。
private readonly int Column5;
它的应用场景是:允许把一个字段设置为常量,但还需要执行一些计算,以确定它的初始值,这是常量无法做到的。
它的规则是:可以在构造函数中给只读字段赋值,但不能在其他地方赋值。
匿名类型
之前的章节,见过使用var关键字实现“类型推断”,var同时还应用于创建匿名类型。所谓匿名类型,是是一个继承自Object且没有名称的类。
var obj = new
{
Name = "daixf",
Age = 40
};
我们可以看到,在定义匿名类型时,需要指定属性名称和值。注意匿名类型的成员是属性而不是字段,可以想想为什么这么设计?我想,是因为遵循设计规范,属性一般是public的,而字段一般是private,两者各司其职。显然匿名类的成员需要被访问,所以应该是public,所以应该定义为属性。
但不是任何情况下,都需要指定创建的匿名类型的属性名的,如果数据来自于其他类的属性,匿名类型会默认使用相同属性名。
var obj1 = new
{
obj.Name,
obj.Age
};
因为匿名类型并没有特定的类型名,编译器为其指定了一个临时的类型名,因此在匿名类型上无法执行反射功能。
结构
上一篇已经讲过,结构和类非常像。结构的特点:
- 结构的定义和类类似,结构也是派生自Object,可定义字段、属性、函数
- 结构是值类型。因为是值类型,所以可以采用值类型的赋值方式而不采用new
- 限制:结构不能继承;结构默认了一个无参构造函数,且不允许显式的定义无参构造函数
- 和类中定义public会员采用属性不同,因为结构本来是小对象,因此多数程序员也倾向于不使用属性,而采用public字段作为成员。这似乎违反了C#通用编程规范(属性public,字段private),但它可以看作规范的例外情况。
部分类(partial)
部分类似乎离我们很远,我在践行“基于Repository框架”的时候,曾经必须用它,因为大量的类需要通过工具软件生成,而工具生成的类又有一部分功能需要手工书写,为了避免手工写的代码被工具软件覆盖,所以就采用了部分类的方式,一个类分为两个文件。但抛弃了Repository框架之后,我就再也没有主动用过部分类。
采用部分类的原因一般有以下几种:
- 避免代码生成工具生成的代码和手写代码的冲突,使用多个部分类代码文件
- 方便多个程序员协同开发,大家修改同一个类却可以锁定不同的文件
- 一个类的功能代码较多,使用部分类对功能进行分类,不同的功能组分布到不同的代码文件中
使用部分类的一个典型就是Winform窗体。一些初学者可能还不知道Form窗体使用了部分类。一个Form窗体就有两个cs代码文件,designer.cs就是由界面设计工具生成的:
使用部分类遵循的规则:
- 关键字的用法:把partial放在class,struct,interface等关键字的前面
- 多个部分类文件,必须定义为相同的namespace
- 多个部分类文件,必须使用相同的修饰符关键字,比如同为public,private
除了部分类,还有“部分方法”的概念,用途差不多,这里先不详述。
静态类(static)
是否定义类为静态类,似乎并不是那么清楚。因为一般我们声明一个静态字段/属性,或者实现一个静态方法,也不代表其所在的类必须是静态类。那么我们什么情况下认为类应该定义为静态类呢?我认为是否定义为静态类,更多的依据编程规范,而不是强制要求。
- 首先明确的一点是,如果类中定义了扩展方法,那么类必须定义为静态类,否则会编译错误
- 如果类的所有成员都是静态成员,那么此类应该声明为静态类(因为已经没有实例成员,不声明为静态类没有实际意义)
- 如果确定不会设计类的实例成员,那么应该声明类为静态类,因为这样编译器会进行强制检查,避免程序员不经意间定义不需要的实例成员。
Object类
所有.Net类都派生自Object类,包括结构(结构首先派生自类System.ValueType,而ValueType类又派生自Object类)。结构也派生自类,这也就好理解为什么struct的定义和class这么像了。
Object作为基类,它的一些成员是都是非常重要的,而且非常常用,简单介绍:
- ToString(),转字符串,常见的是基础类型转string
- GetHashTable(),用于散列表和字典
- Equals()和RefrenceEquals(),和比较运算符“==”一起,三者应用场景值得仔细比较
- Finalize(),类似于C++的析构函数。它和终结器,和Dispose()的关系和区别后面细讲
- GetType(),获取类类型,此功能往往和反射有关
- MemberwiseClone(),浅表复制。所谓浅表复制,是指复制类实例中,所有值类型的“值”,以及所有引用类型的“引用”。
扩展方法
扩展方法应用于:想给某个类增加方法,但却没有类的源码,或者没有对类的修改权限。此时可以使用扩展方法。扩展方法是静态类中的静态方法。对于扩展方法,第一个参数是要扩展的类型,它放在this关键字的后面。这告诉编译器,这个方法是扩展类型的一部分。在这个例子中,string是要扩展的类型。
public static bool IsNullOrEmpty(this string str)
调用:"abc".IsNullOrEmpty()
第三章到此为止就结束了,本章总体上讲了类的组成成员,以及其字段、属性、方法,和各种特性。下章将讲解《继承》。
觉得文章有意义的话,请动动手指,分享给朋友一起来共同学习进步。
欢迎关注本人微信公众号,更及时的关注最新文章(每周三篇原创文章,以及多篇专题文章):
附文:
C#部分类与部分方法
上一篇:解读经典《C#高级编程》第七版 Page68-79.对象和类型.Chapter3
解读经典《C#高级编程》第七版 Page79-93.对象和类型.Chapter3的更多相关文章
- c#高级编程第七版 学习笔记 第一章 .NET体系结构
第一章 .NET体系结构 本章内容: 编译和运行面向.NET的代码 Microsoft中间语言(Microsoft Intermediate Language,MSIL或简称IL)的优点 值 ...
- c#高级编程第七版 学习笔记 第二章 核心c#
第二章 核心C# 本章内容: 声明变量 变量的初始化和作用域 C#的预定义数据类型 在c#程序中使用条件语句.循环和跳转语句执行流 枚举 名称空间 Main()方法 基本的命令行c#编译器选项 使用S ...
- c#高级编程第七版 学习笔记 第三章 对象和类型
第三章 对象和类型 本章的内容: 类和结构的区别 类成员 按值和按引用传送参数 方法重载 构造函数和静态构造函数 只读字段 部分类 静态类 Object类,其他类型都从该类派生而来 3.1 类和结构 ...
- ASP.NET MVC 4高级编程(第4版)
<ASP.NET MVC 4高级编程(第4版)> 基本信息 作者: (美)Jon Galloway Phil Haack Brad Wilson K. Scott All ...
- 《UNIX环境高级编程(第3版)》
<UNIX环境高级编程(第3版)> 基本信息 原书名:Advanced Programming in the UNIX Environment (3rd Edition) (Addison ...
- 【转】apue《UNIX环境高级编程第三版》第一章答案详解
原文网址:http://blog.csdn.net/hubbybob1/article/details/40859835 大家好,从这周开始学习apue<UNIX环境高级编程第三版>,在此 ...
- Linux - Unix环境高级编程(第三版) 代码编译
Unix环境高级编程(第三版) 代码编译 本文地址:http://blog.csdn.net/caroline_wendy 时间:2014.10.2 1. 下载代码:http://www.apuebo ...
- 解读经典《C#高级编程》第七版 Page68-79.对象和类型.Chapter3
前言 新年好,本篇开始进入第三章,<对象和类型>,深刻理解C#的对象,对于使用好.Net类库非常重要. 01 类和结构 从使用角度看,结构和类的区别很小,比如,将结构定义转换为类,只需要将 ...
- Unix环境高级编程第三版中实例代码如何在自己的linux上运行的问题
学习Linux已经有2个月了,最近被期末考试把进度耽误了,前几天把Unix环境高级编程看了两章,感觉对Linux的整体有了一些思路,今天尝试着对第一章涉及到的一个简单的交互式shell编译运行一下,结 ...
随机推荐
- ECharts使用—折线图动态加载
最近需求中用到折线图,单线条,多线交错,之前是散点图,用的是另一个 amcharts.js,这个文档也能找的到,回归早本次重点:ECharts 一.首先引入echarts.common.min.js文 ...
- Ubuntu 16.04更新grub-pc提示脚本/var/lib/dpkg/info/grub-pc.postinst 执行错误
错误信息: $ sudo aptitude upgrade 下列仅部分安装的软件包将被配置: grub-pc 将不会安装,升级或者删除任何软件包. 0 个软件包被升级,新安装 0 个, 0 个将被删除 ...
- html、css基础整理
1.块元素与行内元素之间的转换: HTML可以将元素分类方式分为行内元素.块状元素和行内块状元素三种.这三者是可以互相转换的,使用display属性能够将三者任意转换: (1)display:inli ...
- jquery向Django后台发送数组
在$.ajax中加入 traditional:true, //加上此项可以传数组 后端用 array = request.POST.getlist('ids') #django接收数组 来接收数组
- Android开发者的Anko使用指南(二)之Dialogs
在项目中使用Anko Dialogs dependencies { compile "org.jetbrains.anko:anko-commons:$anko_version" ...
- Think in java(1)
OOP编程思想认为万事万物皆对象,而在设计类(class)的时候,就是从我们生活中或者某些事物中抽象出一个具有共同属性,共同行为的描述(类).在实际的开发中,我们一般会不自觉的这样做:假设有一个人 ...
- 学习Java的进度
这周我们通过老师的讲解带着我们回到了第八周的知识点.lambda表达式也是一种简化程序的好方法,通过回调程序的测试可以对比出lambda 表达式少的不是一两行代码,可以少了类中方法的定义,直接使用.内 ...
- PYTHON黑帽编程 4.1 SNIFFER(嗅探器)之数据捕获--补充
荒废了一个多月了,重新捡起来,手生了不少.发现在<4.1下>的文章里没有 提到pcap库,实在是不应该. 在网络数据分析的工具中,tcpdump绝对是大名鼎鼎,tcpdump底层是libp ...
- SQL Server 存储过程的运用
概述 最近因为业务的需求写了一段时间存储过程,发现之前写的存储过程存在一些不严谨的地方,特别是TRY...CATCH中嵌套事务的写法:虽然之前写的并没有错,但是还是埋藏着很大的隐患在里面.希望这篇文章 ...
- 前端框架本质之探究——以Vue.js为例
问:我们在使用Vue时,实际上干了什么? 答:实际上只干了一件事——new了一个Vue对象.后面的事,都交由这个对象自动去做.就好像按了下开关,机器跑起来了,剩下的事就不用我们再操心了. 各位 ...