本学习主要参考Andrew Troelsen的C#与.NET4高级程序设计,这小节主要述说以下几个东西:

这一小节是上一小节的补充,主要涉及到一下的知识细节:

1、C#方法的各种细节
2、探讨out、ref和params关键字以及可选参数和命名参数
3、方法重载。
4、C#操作数组类型的细节和了解System.Array类类型中包含的功能。
5、枚举结构和结构类型。
6、值类型和引用类型的区别。
7、探讨可空数据类型以及?和??操作符的作用。
 

方法和参数修饰符

和Main方法类似,自定义方法可以有或者没有参数,也可以有或者没有返回值。方法可以在类或结构的范围内实现(还可以在接口类型中设置原型)、并且可以被各种关键字(如internal、virtual、public等)修饰以限制其行为。方法的基本格式如下:
class A
{
    static int Add(int x,int y){return x+y;}
}

接下来总结一下C#的参数修饰符。

1.默认的参数传递行为:

参数传入函数的默认行为是按值传递。简单来说,如果没有为参数标记参数相关的修饰符,数据的副本就会被传入函数。数值数据属于值类型,因此,如果在成员的作用域内改变参数的值,改变的就是调用者数据值的副本,调用者完全不会意识到这种改变。

2.out修饰符:

简单来说,就是输出参数。定义为带有输出参数的方法有义务在退出这个方法前,必须给参数赋一个恰当的值。如,下述方法返回x/y的和到ans中:
static void Add(int x, int y, out int ans)
{
    ans=x+y;
}
out参数有个很有用的用途,调用者可以通过它使用一次方法返回多个返回值。并且,调用一个带有输出参数的方法也需要使用out修饰符。

3.ref修饰符:

说一下我的理解,ref关键字的用法,相当于是使得值类型拥有类似引用类型的功能,通常是改变他们的值。下面是引用参数和输入参数的区别:
输出参数不需要在他们被传递给方法之前初始化,因为方法在退出之前必须为输出参数赋值。而引用参数必须在他们被传递给方法之前初始化,因为实在传递一个对已存在变量的引用。

4.params修饰符:

C#使用params关键字支持参数数组的使用。params关键字可以把可变数量的参数(相同类型)作为单个逻辑参数传给方法。例如如下方法:
static double calculate(params double[] values)
{}
这个方法定义为一个带有double类型参数数组,可以给它传递任意数量的double类型参数。例如:calculate(4.1,4.2,...)
说明:为避免歧义,C#要求方法只支持一个params参数,而且必须是参数列表的最后一个参数。

5.定义可选参数:

大体上就是说,我们可以创建一个包含赋值了默认值的参数。例如下面方法:
static void A(string a, string b="SB")
{}
其中第二个参数就是我们赋值了一个默认值的可选参数。
同样,为了避免歧义,可选参数必须放在方法签名的最后,将可选参数放到非可选参数前面会引发编译错误。

6.使用命名参数调用方法:

同可选参数一样,支持命名参数的主要原因也是为了简化与COM的互操作。
命名参数允许我们在调用方法时以任意顺序指定参数的值,因此我们可以使用冒号操作符通过名称来指定参数而不必按位置传递参数。参数用法如下:例如定义一个传递ConsoleColor参数的B方法。void B(ConsoleColor aaa);那么就可以这样用这个方法:B(aaa:ConsoleColor.White);
如果定义了一个包含可选参数的方法,命名参数就非常有用,调用该方法的时候,我们直接给命名参数赋值就行了,不用再指定可选参数的值了。

7.成员重载:

和其他的面向对象语言一样,C#允许方法重载。简而言之,当我们定义了一组名字相同的成员是,如果他们的参数数量(或类型)不同,这样的成员就叫做被重载的成员。
例如同样名字的B方法,传递的参数一个int类型,一个是double类型,这也是允许的。B(int aa)和B(double aa)是两个不同的方法。通过参数的类型不同来区分。
 

C#中的数组操作

数组是一组通过数字索引来访问的数据项。更准确的说,数组是一组相同类型的数据点(int数组,string数组等)。数组定义类似下面:
int[] myIntArray;
用法如:int[] myIntArray=new int[3];
赋值如:int[0]=199;

1.C#数组初始化语法:

除了逐字填充数组外,还可以用数组初始化语法来填充数组,通过在花括号{}内指定每一个数组项来实现,用法如下:
string[] myStrArray = new string[] { "A", "B" };

2.隐式类型本地数组:

var同样可以用来定义隐式类型本地数组,定义方法如下(注意,数组的元素类型必须一样,所以即使是隐式类型数组,内里元素的类型也要一致,因为编译的时候会确定类型):
var myStrArray = new[] { "A", "B" };

3.定义object数组:

因为System.Object是.net类型系统中所有类型的最终基类,这样的话,如果我们定义了一个object数组,它的子项就可以是任何东西。用法如下:
object[] obj = new object[] { 1, "A", 'a' };

4.使用多维数组:

多维数组主要有两种,一种叫做矩形数组。一种叫做交错数组。
矩形数组排列是以矩阵的形式,声明如下:int[,]=new int[6,6];表示声明了一个6*6的矩形数组。
交错数组,也就是数组的数组。声明如下:int[][] = new int[5][];声明了一个具有五个不同数组的数组。

5.数组作为参数(和返回值)

只要我们创建了一个数组,就完全可以把它当做参数进行传递或者作为成员返回值接受。如下:
static string[] A()
{
    string[] B = new string[]{"aaa"};
    return B;
}

6.System.Array基类:

我们创建的每一个数组都从System.Array类获得很多功能。使用这些公共成员,我们就能使用统一的对项模型来操作数组。(Clear(),Sort()等)例如,反转一个数组,操作如下:
string[] A = new string[]{"A","B"};
反转用法:Array.Reverse(A);
 

枚举类型

在构建系统的时候,创建一组符号名来对应已知的数字值会很方便。枚举可以帮助我们实现这个功能。默认情况下,枚举值的存储类型是System.Int32。定义如下:
enum E
{
sss=12,//表示从12开始
aaa,//真实值13
bb//真实值是14
}

1.控制枚举的底层存储:

枚举值的存储类型也可以进行改变,如果我们将枚举值存储类型设置为byte而不是int,那么可以这么写:
enum E:byte
{
aaa=10,
B=1,
CC=100
}
注意,如果我们枚举值超出了枚举类型的范围,那么就会导致编译错误。如上,如果让枚举值等于999就会引发编译错误。
 

2.声明枚举变量:

因为枚举只不过是用户自定义的类型,我们可以把它们作为函数的返回值、方法参数、本地变量等。

3.System.Enum类型:

.net枚举从该类获得了很多功能,这个类定义了许多用来查询和转换某个枚举的方法。例如Enum.GetUnderlyingType()方法,它用来返回用于保存枚举类型值的数据类型。

4.动态获取枚举的名称/值对:

所有的枚举都支持ToString方法,它返回当前枚举值的字符串名。而另一个方法GetValue则可以返回枚举的值。
 

结构类型

同C语言中的结构一样,结构不只是一组名称值对,结构式可以包含许多数据字段和操作这些字段的成员的类型。
定义结构:
struct A
{
    public int x;
    public void Disp()
    {
        Console.WriteLine("x={0}",x);
    }
}
创建结构变量:第一种可以直接以结构名定义,如A a;但是这种必须为结构中的每个公共字段赋值,否则就会出错。另一种方法是用new关键字来创建结构变量,它会调用默认的构造函数,不接受任何输入参数。A a = new A();
 

值类型和引用类型

C#的结构和数组、字符串以及枚举全都派生自System.ValueType。而该来的作用是确保所有的派生类都分配在栈上而不是垃圾回收堆上。创建和销毁分配再栈上的数据都很快,因为它的生命周期是由定义的作用域决定的,而分配在堆上的数据由.net拉基回收器监控,其生命周期的决定因素有很多。
从功能上说,该类的唯一目的是,重写由System.Object定义的虚方法来使用基于值的而不是基于引用的语法。
由于值类型使用基于值的语法,结构的生命周期是可以预测的,当结构变量离开定义域的范围时,它就会立即从内存中移除。

1.值类型、引用类型和赋值操作符:

值类型赋值(例如结构),在栈上会保留两个副本,给其中一个操作改变值,不会影响另一个副本的值。
和栈中的值类型相比,当对引用类型(类类型)应用赋值操作符时,我们就是在内存中重定向引用变量的指向。他们相当于引用了托管堆中的同一个对象,当改变其中一个的值的时候,另一个也会改变。

2.包含引用类型的值类型:

默认情况下,当值类型包含其他引用类型时,赋值将生成一个引用的副本。这样就有两个独立的结构,但每一个都包含指向内存中同一个对象的引用(浅复制)。如果想要执行一直‘深复制’也就是让副本不受自己影响,即将内部引用的状态完全复制到一个新对象中时,需要实现ICloneable接口。

3.按值传递引用类型:

大概就是将类作为参数传递给方法,并且在方法内部进行多次修改类的参数和重新赋值。例如:
class A
{
    public int a;
    public A(int aa)
    {
        a = aa;
    }
}
方法B如下:
void B(A a)
{
    a.a = 100;//表示改变类内部的值,起作用
    a=new A(99);//表示给类重新赋值,不起作用
}
因为, 在这里,传递的值其实是复制了调用者对象的引用。由于B方法与调用者指向同一个对象,所以改变对象的状态数据是可能的,但是无法把引用重新赋值给一个新对象。

4.按引用传递引用类型:

参考上面的例子,如果有一个C方法,它是按照引用传递引用类型。如:
void C(ref A a)
{
    a.a = 100;//表示改变类中a的值,起作用
    a=new A(99);//表示给a实例分配了一个堆上新的对象,起作用
}
按引用传递引用类型时需要记住的黄金规则如下:
1,如果按引用传递引用类型,被调用者可能改变对象的状态数据的值和所引用的对象。
2,如果按值传递引用类型,被调用者可能改变对象的状态数据的值,但不能改变所引用的对象。
 

C#可空类型

现在我们应该记得所有数值数据类型(包括Boolean数据类型)都是值类型,按照规则,null用来建立一个空的对象引用,所以值类型永远不可以被赋值为null。
为了定义一个可空的变量类型,应在底层数据类型中添加问号(?)作为后缀。注意,这种语法只对值类型是合法的。如果试图创建一个可空的引用类型,包括字符串,都是遇到编译错误。同非空变量一样,局部可空变量必须赋一个初始值。

1.使用可空类型:

涉及到数据库编程时,可空数据类型可能特别有用,因为一个数据表中的列可能有意是空的。定义如下:public int? a=null;
返回可空类型:
public int? geta()
{
    return a;
}

2.??操作符:

关于可空类型需要知道的最后一点是,可以使用??操作符。在获得的值实际上是null时,我们可以用这个操作符给一个可空类型赋值。
例如,当上述方法返回值为null的时候,可以给本地变量赋值为100:
int a = geta() ?? 100;
使用??操作符的好处是,它比传统的if/else条件的写法更加紧凑。不过也可以使用如下代码确保如果值为空,则设置默认的100:
int a= geta();
if(!a.HasValue)
    a = 100;
Console.WriteLine("a的值是:{0}",a);
 

小结:

本小结主要总结了可以用来构建自定义方法的C#关键字,默认情况下参数按值传递。然而,如果参数被标记为ref或者out,我们可以按引用进行传递。除此之外,我还总结了关于方法重载,以及有关数组、枚举和结构如何在C#中定义和在.net类库中表示的方法。最后我们俺就了值类型和引用类型细节,以及包括当作为参数传入方法后,他们如何反应,和如何使用?以及??操作符来和可空数据类型进行交互。

3、C#核心编程结构下的更多相关文章

  1. 2、C#核心编程结构

     本学习主要参考Andrew Troelsen的C#与.NET4高级程序设计,这小节主要述说以下几个东西: Hello World的Main方法: 利用VS2010新建一个控制台应用程序Hello W ...

  2. 【windows核心编程】 第八章 用户模式下的线程同步

    Windows核心编程 第八章 用户模式下的线程同步 1. 线程之间通信发生在以下两种情况: ①    需要让多个线程同时访问一个共享资源,同时不能破坏资源的完整性 ②    一个线程需要通知其他线程 ...

  3. 【Windows】windows核心编程整理(下)

    windows核心编程整理(上) windows核心编程整理(下) 线程的堆栈 每当创建一个线程时,系统就会为线程的堆栈(每个线程有他自己的堆栈)保留一个堆栈空间区域,并将一些物理存储器提交给这个以保 ...

  4. 用户模式下的线程同步的分析(Windows核心编程)

    线程同步 同一进程或者同一线程可以生成许多不同的子线程来完成规定的任务,但是多个线程同时运行的情况下可能需要对某个资源进行读写访问,比如以下这个情况:创建两个线程对同一资源进行访问,最后打印出这个资源 ...

  5. Qt on Android 核心编程

    Qt on Android 核心编程(最好看的Qt编程书!CSDN博主foruok倾力奉献!) 安晓辉 著   ISBN 978-7-121-24457-5 2015年1月出版 定价:65.00元 4 ...

  6. windows核心编程 - 线程同步机制

    线程同步机制 常用的线程同步机制有很多种,主要分为用户模式和内核对象两类:其中 用户模式包括:原子操作.关键代码段 内核对象包括:时间内核对象(Event).等待定时器内核对象(WaitableTim ...

  7. windows核心编程---第九章 同步设备IO与异步设备IO之同步IO

    同步设备IO 所谓同步IO是指线程在发起IO请求后会被挂起,IO完成后继续执行. 异步IO是指:线程发起IO请求后并不会挂起而是继续执行.IO完毕后会得到设备的通知.而IO完成端口就是实现这种通知的很 ...

  8. windows核心编程---第八章 使用内核对象进行线程同步

    使用内核对象进行线程同步. 前面我们介绍了用户模式下线程同步的几种方式.在用户模式下进行线程同步的最大好处就是速度非常快.因此当需要使用线程同步时用户模式下的线程同步是首选. 但是用户模式下的线程同步 ...

  9. python核心编程第二版笔记

    python核心编程第二版笔记由网友提供:open168 python核心编程--笔记(很详细,建议收藏) 解释器options:1.1 –d   提供调试输出1.2 –O   生成优化的字节码(生成 ...

随机推荐

  1. 12306官方火车票Api接口

    2017,现在已进入春运期间,真的是一票难求,深有体会.各种购票抢票软件应运而生,也有购买加速包提高抢票几率,可以理解为变相的黄牛.对于技术人员,虽然写一个抢票软件还是比较难的,但是还是简单看看123 ...

  2. 前端框架 EasyUI (0) 重新温习(序言)

    几年前,参与过一个项目.那算是一个小型的信息管理系统,BS 结构的,前端用的是基于 jQuery 的 EasyUI 框架. 我进 Team 的时候,项目已经进入开发阶段半个多月了.听说整个项目的框架是 ...

  3. ASP.NET Core 之 Identity 入门(三)

    前言 在上一篇文章中,我们学习了 CookieAuthentication 中间件,本篇的话主要看一下 Identity 本身. 最早2005年 ASP.NET 2.0 的时候开始, Web 应用程序 ...

  4. 高性能Javascript--脚本的无阻塞加载策略

    Javascript在浏览器中的性能,可以说是前端开发者所要面对的最重要的可用性问题. 在Yahoo的Yslow23条规则当中,其中一条是将JS放在底部 .原因是,事实上,大多数浏览器使用单进程处理U ...

  5. 结巴分词3--基于汉字成词能力的HMM模型识别未登录词

    作者:zhbzz2007 出处:http://www.cnblogs.com/zhbzz2007 欢迎转载,也请保留这段声明.谢谢! 1 算法简介 在 结巴分词2--基于前缀词典及动态规划实现分词 博 ...

  6. [C#] C# 知识回顾 - 学会处理异常

    学会处理异常 你可以使用 try 块来对你觉得可能会出现异常的代码进行分区. 其中,与之关联的 catch 块可用于处理任何异常情况. 一个包含代码的 finally 块,无论 try 块中是否在运行 ...

  7. Discuz NT 架构剖析之Config机制

    接触了Discuz NT! 一段时间了,是时候做个总结了,标题好霸气,有木有? 都是托园子里的大牛代振军的福啊,哈哈哈哈. 首先论坛的信息不是完全存储在数据库里面的,一部分信息存储在config文件里 ...

  8. setCapture、releasCapture 浅析

    1. setCapture 简介 setCapture可以将鼠标事件锁定在指定的元素上,当元素捕获了鼠标事件后,该事件只能作用在当前元素上. 以下情况会导致事件锁定失败: 当窗口失去焦点时,锁定的事件 ...

  9. 去IOE的一点反对意见以及其他

    某天在机场听见两老板在聊天,说到他们目前销售的报表老跟不上的问题,说要请一个人,专门合并和分析一些发过来的excel表格,我真想冲上去说,老板,你需要的是一个信息处理的系统,你需要咨询么.回来一直耿耿 ...

  10. SAP CRM 显示消息/在消息中进行导航

    向用户展示消息,在任何软件中都是十分重要的. 在SAP CRM WEB UI中展示消息,不是一项很难的任务,只需要创建消息并在之后调用方法来显示它 消息类和消息号: 我在SE91中创建了如下的消息类和 ...