前言

新年好,本篇开始进入第三章,《对象和类型》,深刻理解C#的对象,对于使用好.Net类库非常重要。

01

类和结构

从使用角度看,结构和类的区别很小,比如,将结构定义转换为类,只需要将关键字struct改为class即可。创建结构的时候,也同样可以用关键字new。它们的本质区别是,结构是值类型,存储在栈上,而类存储在堆上。

但我还没碰到什么情况下需要使用结构。因为一般的业务代码,在设计时很难提炼出足够可泛化的含义,而如果只是少数情况下采用结构,对性能的提升微乎其微。但我们也可以发现在.Net框架下,还是比较多的使用了结构,这估计是因为:

  1. .Net作为千万程序员都在使用的框架和类库,性能上精益求精就有必要了
  2. 其次,我们发现.Net使用结构是成体系的,比如Point,Size, Rectangle等,大量的“形状”都采用了结构,这从对象化的设计角度看就非常有意义了

02

类的数据和函数称为类的成员。清晰的理解类的“数据成员”和“函数成员”,对于用好反射功能非常重要。因为反射针对不同的成员类型有不同的功能实现。

数据成员

数据成员是包含类的数据——字段、常量和事件的成员。特别注意的是,“事件”是数据成员。为什么呢?这后面会讲到,事件是一种特殊的委托,而委托实际上是类,所以事件的实例当然是数据。

函数成员

函数成员提供了操作类中数据的某些功能,包括方法、属性、构造函数和终结器(finalizer)、运算符以及索引器。方法、属性、构造函数大家经常碰到,会比较好理解。而对终结器、运算符、索引器来说,它们都是“特殊的方法”。

属性:函数组,即get函数和set函数的组合。

终结器:类似于构造函数,如果构造函数名为“FuncA”,终结器则名为“~FuncA”,类似Java的析构函数finalize()。

运算符:类的运算符可以重载,实现自定义功能,那么运算符归类为函数,也就好理解了。

索引器:将对象以集合的方式访问。

方法 / ref / out

方法的参数传递值得探讨。函数的参数传递有“值传递”和“引用传递”两种方式。在C#中,除非明确带关键字,所有的参数都通过值来传递。这让我们会产生一个疑问,因为在实际编程中,往往会使用引用类型作为参数,而又没有使用ref关键字时,此时传递的到底是值呢还是引用呢?答案是:传递的还是值。值传递时,仍然进行了值的复制,但复制的是“引用”,而不是对象本身。所以,我们也可以推论说:对于传递引用类型的参数,加不加ref,效果都同加ref是一样的。

和ref对应,还有个out关键字。使用out关键字定义的参数,out会强制要求函数中将变量初始化或赋值后再输出。实际上,使用或者不使用参数关键字,对应了实际使用方法中的三种常见场景:

  1. 不带关键字:传入参数,不传出
  2. ref关键字:传入参数,再传出
  3. out关键字:不接受参数传入,但传出参数。out和ref一样,传递的是引用。

命名参数

使用命名参数的作用是,书写调用时,参数的书写顺序不再受限制。比如:定义时为:

public void Test(int arg1, int arg2)

调用时可以为:

user.Test(arg2: 1, arg1: 2);

不过我没有用过命名参数,因为实在找不到应用它的场景。但我回想起在之前公司的基于Repository的架构下,倒是能为它找到用武之地。为什么呢?因为在Repository架构下,为遵循架构规则,需要为每一个表建立对外的业务访问接口,而复杂的业务需求又导致接口需要大量参数的方法重载,比如一个方法可能有超过10个参数定义。这时候,在调用方法的时候,万一有一两个参数写错了顺序,就会导致程序的bug。为了避免这种问题,使用命名参数,明确的指定 参数名:值,相当于程序员在写代码时就进行了明确的参数名检查,从而避免bug。但这种问题,是由于不合理的Repository架构导致的,当废弃了Repository架构后,这种应用场景不复存在。

可选参数

可选参数如:public void Test(int arg1, int arg2 = 10)

可选参数必须是方法定义的最后一个参数。

方法重载

书中说到“如果不能使用可选参数,就可以使用方法重载”。这说明了语言设计的倾向性。即原则上应该多使用可选参数,而避免过多的使用重载,毕竟方法重载的“代码复用度”一般不如可选参数。

何为“方法的重载”?方法的重载,即一个方法的几个版本有不同的签名(即,方法名相同,但参数的个数和/或类型不同,注:不包括返回值)。方法重载的参数限制:

  1. 两个方法不能仅在返回类型上有区别。
  2. 两个方法不能仅根据参数是声明为ref还是out来区分。

属性

属性(Property)的概念是:它是一个方法或一对方法,在客户端代码看来,它(们)是一个字段。这个定义非常有意思。所谓“客户端代码”,就是调用属性的代码。在调用者看来,属性和字段并无区别。区别在于内部,属性可以对其get/set访问器进行代码定制,从而实现更复杂的需求。

因为属性是特殊的方法,那么要实现一个功能时,是应该定义为属性还是定义为方法,这在12月25日的文章中有深入分析。

在有不少老的代码里,属性是这么定义的:

string column1;

public string Column1

{

get

{

return column1;

}

set

{

column1 = value;

}

}

这是因为在.Net2.0时,对属性的定义还没那么方便。虽然它已经比Java的get,set方法好多了,但还是比较繁琐。在更新版本的.Net下,已经可以使用这种方式定义属性:

public int Column1 { get; set; }

这叫做“自动实现的属性”。实际上它只是一个语法糖,本质并没有变。

get,set访问器可以带上修饰符。如果没有带上修饰符,那么它使用的是属性的修饰符。比如可以:

public int Column1 { get; private set; }

public int Column2 { get; }

public int Column3 { private get; set; }    //只写属性,不应该出现

内联

因为属性本质是方法,我们也看到实际使用中,大多数属性都是采用“自动实现属性”的,那么为了实现属性的偶尔才使用的“访问限制”功能,而将“字段访问”改为“方法”访问,会增加方法访问的额外开销吧?值得吗?

我们不用担心这个问题。因为.Net编译器已经将属性访问代码编译为“内联代码”而不是“函数调用”代码。

类是对象化编程的基本概念,内容非常多。下一篇将继续讲讲:构造函数、只读字段、匿名类型、结构详解、部分类、静态类、Object类、扩展方法,等。

觉得文章有意义的话,请动动手指,分享给朋友一起来共同学习进步。

欢迎关注本人微信公众号,更及时的关注最新文章(每周三篇原创文章,以及多篇专题文章):

附文:

c# 方法参数(传值,传引用,ref,out,params,可选参数,命名参数)

C#中的字段与属性的区别及属性的作用

上一篇:解读经典《C#高级编程》第七版 Page50-68.核心C#.Chapter2

解读经典《C#高级编程》第七版 Page68-79.对象和类型.Chapter3的更多相关文章

  1. c#高级编程第七版 学习笔记 第一章 .NET体系结构

    第一章      .NET体系结构 本章内容: 编译和运行面向.NET的代码 Microsoft中间语言(Microsoft Intermediate Language,MSIL或简称IL)的优点 值 ...

  2. c#高级编程第七版 学习笔记 第二章 核心c#

    第二章 核心C# 本章内容: 声明变量 变量的初始化和作用域 C#的预定义数据类型 在c#程序中使用条件语句.循环和跳转语句执行流 枚举 名称空间 Main()方法 基本的命令行c#编译器选项 使用S ...

  3. c#高级编程第七版 学习笔记 第三章 对象和类型

    第三章 对象和类型 本章的内容: 类和结构的区别 类成员 按值和按引用传送参数 方法重载 构造函数和静态构造函数 只读字段 部分类 静态类 Object类,其他类型都从该类派生而来 3.1 类和结构 ...

  4. 解读经典《C#高级编程》第七版 Page79-93.对象和类型.Chapter3

    前言 本篇我们继续讲解本章其余的部分:构造函数.只读字段.匿名类型.结构详解.部分类.静态类.Object类.扩展方法,等. 01 类 构造函数 构造函数是一种特殊的方法: 与类同名 没有返回值,甚至 ...

  5. ASP.NET MVC 4高级编程(第4版)

    <ASP.NET MVC 4高级编程(第4版)> 基本信息 作者: (美)Jon Galloway    Phil Haack    Brad Wilson    K. Scott All ...

  6. 《UNIX环境高级编程(第3版)》

    <UNIX环境高级编程(第3版)> 基本信息 原书名:Advanced Programming in the UNIX Environment (3rd Edition) (Addison ...

  7. 【转】apue《UNIX环境高级编程第三版》第一章答案详解

    原文网址:http://blog.csdn.net/hubbybob1/article/details/40859835 大家好,从这周开始学习apue<UNIX环境高级编程第三版>,在此 ...

  8. Linux - Unix环境高级编程(第三版) 代码编译

    Unix环境高级编程(第三版) 代码编译 本文地址:http://blog.csdn.net/caroline_wendy 时间:2014.10.2 1. 下载代码:http://www.apuebo ...

  9. Unix环境高级编程第三版中实例代码如何在自己的linux上运行的问题

    学习Linux已经有2个月了,最近被期末考试把进度耽误了,前几天把Unix环境高级编程看了两章,感觉对Linux的整体有了一些思路,今天尝试着对第一章涉及到的一个简单的交互式shell编译运行一下,结 ...

随机推荐

  1. HTTP lab01 做一个简单的测试用 web页面

      做一个简单的测试用 web页面     1.安装httpd服务   yum install httpd   安装完httpd服务后,系统就自动生成了/var/www/html目录     创建一个 ...

  2. vue监听滚动事件-元素固定位置显示

    1.监听滚动事件 用VUE写一个在控制台打印当前的scrollTop用来测试是否执行: mounted () { window.addEventListener('scroll', this.hand ...

  3. 我们的爬虫从pyspider开始说起(一)

    看各种爬虫文献也有好几天了,总是感觉下不了手,总结一句“提笔忘字,总是因为看的太多而写的太少”.所以从现在开始,把看到的想到的,需要总结的东西慢慢的都沉淀下来,扎扎实实的走好每一步. 先来说这几天遇到 ...

  4. HDU 2147 P/N博弈

    点这里去做题 如图 找必胜点和必败点, 1.终点为必胜点 2.所有能一步走到必胜点的都是必败点 3.每一步都只能走到必败点的是必胜点 #include<bits/stdc++.h> usi ...

  5. hightopo自己用开源的方案重构一遍

    经过一年多的学习吧前面路上的坑基本算踩过一遍了 所以下面计划吧hightopo网站上的demo用自己的方式重新写一遍

  6. Eclipse下用NDK编译生成so文件

      我们在安装环境的时候安装了NDK,可以在eclipse下直接生成so文件.NDK的压缩包里面自带了一些sample工程,NDK的文件直接解压到某个目录下即可. 第一次生成so文件的时候,我们先使用 ...

  7. CENTOS7常用的基础命令集合(一)

    目录(?)[-] CentOS7 常用命令集合 常用命令 文件与目录操作 查看文件内容 文本内容处理 查询操作 压缩解压 yum安装器 网络相关 系统相关 系统服务启动相关 防火墙相关 RPM包管理 ...

  8. MySQL--MHA与GTID

    ##==========================================## MySQL 5.6版本引入GTID来解决主从切换时BINLOG位置点难定位的问题,MHA从0.56版本开始 ...

  9. configSections必须是根节点下第一个节点

    对webconfig文档进行配置,添加了一个节点configSectionS,添加时,我自个想,按节点的名称以字母排序,就放在appSettings节点下. 谁知,在程序运行时,出现了错误: 参考上面 ...

  10. Java核心技术卷一基础知识-第2章-Java程序设计环境-读书笔记

    第2章 Java程序设计环境 本章内容: 安装Java开发工具箱 使用集成开发环境 选择开发环境 运行图形化应用程序 使用命令行工具 建立并运行applet本章主要介绍如何安装Java开发工具箱(JD ...