泛型

CollectionClass<ItemClass> items = new CollectionClass<ItemClass>();
items.Add(new ItemClass());

泛型并不限于类,还可以创建泛型接口、泛型方法(可以在非泛型类上定义),甚至泛型委托。这将极大地提高代码的灵活性,正确使用泛型可以显著缩短开发时间。

可空类型

有时让值类型为空是很有用的(尤其是处理数据库时), 泛型使用System.Nullable类型提供了使值类型为空的一种方式。例如:

System.Nullable<int> nullableInt;
nullableInt = null; if (nullableInt == null)
{
...
} if (nullableInt.HasValue)
{
...
}

这不适用于引用类型,即使引用类型有一个HasValue 属性,也不能使用这种方法,因为引用类型的变量值为 null,就表示不存在对象,当然就不能通过对象来访问这个属性,否则会抛出一个异常。

可空类型非常有用,以致于修改了C#语法。声明可空类型的变量不使用上述语法,而是使用下面的语法:

int? nullableInt;

int?是System.Nullable的缩写,但更便于读取。

??运算符

下面两个表达式是的作用是等价的:

op1 ?? op2
op1 == null ? op2 : op1

常用泛型类型

类 型 说 明
List T 类型对象的集合
Dictionary<K, V> 与K 类型的键值相关的V 类型的项的集合

List

List<T> myCollection = new List<T>();
成员 说明
int Count 该属性给出集合中项的个数
void Add(T item) 把一个项添加到集合中
void AddRange(IEnumerable) 把多个项添加到集合中
IList AsReadOnly() 给集合返回一个只读接口
int Capacity 获取或设置集合可以包含的项数
void Clear() 删除集合中的所有项
bool Contains(T item) 确定item是否包含在集合中
void CopyTo(T[] array, int index) 把集合中的项复制到数组array中,从数组的索引index 开始IEnumerator GetEnumerator() 获取一个IEnumerator实例,用于迭代集合。注意,返回的接口强类型化为T,所以在foreach 循环中不需要类型转换
int IndexOf(T item) 获取item的索引,如果集合中并未包含该项,就返回−1
void Insert(int index, T item) 把item插入到集合的指定索引位置上
bool Remove(T item) 从集合中删除第一个item,并返回true;如果item不包含在集合中,就返回false
void RemoveAt(int index) 从集合中删除索引index 处的项

List还有个Item 属性,允许进行类似于数组的访问,如下所示:

T itemAtIndex2 = myCollectionOfT[2];

排序

要针对List排序, 可以在要排序的类型上提供IComparable接口, 或者提供IComparer接口。另外,还可以提供泛型委托,作为排序方法。从了解工作原理的角度来看,这非常有趣,因为实现上述接口并不比实现其非泛型版本更麻烦。

一般情况下,给列表排序需要有一个方法来比较两个T 类型的对象。要在列表中搜索,也需要一个方法来检查T 类型的对象,看看它是否满足某个条件。定义这样的方法很简单,这里给出两个可以使用的泛型委托类型:

  • Comparison:这个委托类型用于排序方法,其返回类型和参数如下:
int method(T objectA, T objectB)
  • Predicate:这个委托类型用于搜索方法,其返回类型和参数如下:
bool method(T targetObject)

Dictionary<K, V>

这个类型可以定义键/值对的集合。与本章前面介绍的其他泛型集合类型不同,这个类需要实例化两个类型,分别用于键和值,以表示集合中的各个项。

事件

订阅一个事件的含义是提供代码,在事件发生时执行这些代码,它们称为事件处理程序。

单个事件可供多个处理程序订阅,在该事件发生时,这些处理程序都会被调用,其中包括引发该事件的对象所在的类中的事件处理程序,但事件处理程序也可能在其他类中。

事件处理程序本身都是简单的方法。对事件处理方法的唯一限制是它必须匹配于事件所要求的返回类型和参数。这个限制是事件定义的一部分,由一个委托指定。

定义事件

在定义事件前,必须先定义一个委托类型,以用于该事件,这个委托类型指定了事件处理方法必须拥有的返回类型和参数。

public delegate void MessageHandler(string messageText);

定义了委托(或者找到合适的现有委托)后,就可以定义事件。

public event MessageHandler MessageArrived;

以这种方式声明了事件后,就可以引发它,方法是按名称来调用它,就好像它是一个其返回类型和参数是由委托指定的方法一样。

MessageArrived("This is a message.");

如果定义该委托时不包含任何参数,就可以使用下面的代码:

MessageArrived();

订阅事件的类是Display,它包含一个方法DisplayMessage(),其定义如下所示:

public class Display
{
public void DisplayMessage(string message)
{
Console.WriteLine("Message arrived: {0}", message);
}
}

这个方法匹配于委托类型(而且是公共的, 如果类不是生成该事件的类,则其事件处理程序就必须是公共的),所以可以用它来响应MessageArrived 事件。

把它们关联起来,开始执行任务。

MessageArrived += new MessageHandler(myDisplay.DisplayMessage);

多用途事件处理程序

Timer.Elapsed 事件的委托包含了事件处理程序中常见的两类参数,如下所示:

  • object source——引发事件的对象的引用

  • ElapsedEventArgs e——由事件传送的参数

在这个事件(以及许多其他的事件)中使用 object 类型参数的原因是,我们常常要为由不同对象引发的几个相同事件使用同一个事件处理程序,但仍要指定哪个对象生成了事件。

EventHandler和泛型EventHandler类型

匿名方法

初始化器

当构造函数不能完全初始化一些参数和属性时,可以使用初始化器(格式如下):

<ClassName> <variableName> = new <ClassName>
{
<propertyOrField1> = <value1>,
<propertyOrField2> = <value2>,
...
<propertyOrFieldN> = <valueN>
};

集合初始化器

List<Curry> curries = new List<Curry>();
curries.Add(new Curry("Chicken", "Pathia", 6));
curries.Add(new Curry("Vegetable", "Korma", 3));
curries.Add(new Curry("Prawn", "Vindaloo", 9));

可以用如下代码替换:

List<Curry> moreCurries = new List<Curry>
{
new Curry
{
MainIngredient = "Chicken",
Style = "Pathia",
Spiciness = 6
},
new Curry
{
MainIngredient = "Vegetable",
Style = "Korma",
Spiciness = 3
},
new Curry
{
MainIngredient = "Prawn",
Style = "Vindaloo",
Spiciness = 9
}
};

类型推理

关键字var

var <varName> = <value>;

在这行代码中,变量隐式地类型化为 value 的类型。注意,类型的名称并不是 var。

依赖编译器去确定变量的类型。

注意:如果编译器不能确定用 var 声明的变量类型,代码就不会编译。因此,在用 var 声明变量时,必须同时初始化该变量,因为如果没有初始值,编译器就不能确定变量的类型。

动态查找

C#处理另一种语言创建的对象时,显得很笨拙。例如,假定代码从JavaScript 中获得了一个带Add()方法的对象,该方法把两个数字加在一起。如果没有动态查找功能,调用这个方法的代码就如下所示:

ScriptObject jsObj = SomeMethodThatGetsTheObject();
int sum = Convert.ToInt32(jsObj.Invoke("Add", 2, 3));

ScriptObject 类型(这里不深入探讨)提供了一种访问 JavaScript 对象的方式,但不能执行如下操作:

int sum = jsObj.Add(2, 3);

动态查找功能,它允许编写上述代码。

动态类型

C# 4 引入了dynamic 关键字,以用于定义变量。例如:

dynamic myDynamicVar;

与前面介绍的 var 关键字不同,的确存在 dynamic 类型,所以在声明 myDynamicVar 时,无需初始化它的值。

dynamic 类型不同寻常之处是,它仅在编译期间存在,在运行期间它会被System.Object 类型替代。

一旦有了动态变量,就可以继续访问其成员(这里法有列出实际获取变量值的代码)。

myDynamicVar.DoSomething("With this!");

无论怎样这行代码都会编译。但是如果请求的成员不存在,执行这行代码时会生成一个异常

高级参数方法

可选参数

C++中的默认参数值。

参数命名

可以指定某个可选参数赋值,通过参数名。

拓展方法

要求:

  • 方法必须是静态的。

  • 包含它的类也必须是静态的。

  • 方法必须包含一个参数,表示调用扩展方法的类型实例(这个参数在这里称为实例参数)。

  • 实例参数必须是为方法定义的第一个参数。

  • 除了this 关键字之外,实例参数不能有其他修饰符。

public static class ExtensionClass
{
public static <ReturnType> <ExtensionMethodName>(
this <TypeToExtend> instance)
{
...
}
}

导入了包含静态类(其中包括此方法)的名称空间后(也就是使扩展方法变得可用), 就可以编写如下代码:

<TypeToExtend> myVar;
// myVar is initialized by code not shown here.
myVar.<ExtensionMethodName>();

这个调用实际上与下面的调用相同,但语法更筒单:

<TypeToExtend> myVar;
// myVar is initialized by code not shown here.
ExtensionClass.<ExtensionMethodName>(myVar);

Lambda 表达式

用delegate 关键字定义内联的匿名方法:

myTimer.Elapsed +=
delegate(object source, ElapsedEventArgs e)
{
Console.WriteLine(
"Event handler called after {0} milliseconds.",
(source as Timer).Interval);
};

运用 Lambda 表达式来写这段代码:

myTimer.Elapsed += (source, e) => Console.WriteLine(
"Event handler called after {0} milliseconds.",
(source as Timer).Interval);

Lambda 表达式由3 个部分组成:

  • 放在括号中的参数列表(未类型化)

  • =>运算符

  • C#语句

多行代码用花括号括起来,有返回值需要 return 语句,不像单行代码(一个表达式)编译器会自己作出判断,不用写出 return 。

Lambda 表达式用作委托

一般可以把拥有至多8 个参数的Lambda 表达式表示为如下泛型类型, 它们都在System 命名空间中定义:

  • Action 表示的Lambda 表达式不带参数,返回类型是void

  • Action<>表示的Lambda 表达式有至多8 个参数,返回类型是void

  • Func<>表示的Lambda 表达式有至多8 个参数,返回类型不是void

Action<>有至多 8 个泛型类型的参数,分别用于 Lambda 表达式的 8 个参数,Func<>有至多 9个泛型类型的参数,分别用于Lambda 表达式的8 个参数和返回类型。在Func<>中,返回类型总是在列表的最后。

下面的Lambda 表达式:

(int paramA, int paramB) => paramA + paramB

可以表示为Func<int, int, int>类型的委托,因为它有两个int 参数,返回类型是int。

【备忘】C#语言基础-2的更多相关文章

  1. nodejs备忘总结(一) -- 基础入门

    什么是NodeJS JS是脚本语言,脚本语言都需要一个解析器才能运行.对于写在HTML页面里的JS,浏览器充当了解析器的角色.而对于需要独立运行的JS,NodeJS就是一个解析器. 每一种解析器都是一 ...

  2. 【备忘】WPF基础

    XAML 为了避免生成用户界面(GUI)的代码和基于用户操作执行的代码混合在一起. 名称空间 值得注意的名称空间: xmlns="http://schemas.microsoft.com/w ...

  3. Linux基础之常用基本命令备忘

    Linux基础之常用基本命令备忘 PWD   查询当前所在Linux上的位置 /         根目录 CD(change directory)切换目录  语法 CD /(注意添加空格)   LS ...

  4. UITextView -- 基础备忘

    UITextView 这篇文章只涉及到基本的使用,日后会写一些关于结合TextKit的备忘 基本属性 let screenSize = UIScreen.mainScreen().bounds.siz ...

  5. HTML5终极备忘大全

    二.文字备忘之标签 HTML5中新增的标签 <article> 定义文章 <aside> 定义页面内容旁边的内容 <audio> 定义声音内容 <canvas ...

  6. [转] HTML5终极备忘大全(图片版+文字版)---张鑫旭

    by zhangxinxu from http://www.zhangxinxu.com本文地址:http://www.zhangxinxu.com/wordpress/?p=1544 一.前言兼图片 ...

  7. Express模版引擎hbs备忘

    最近几天折腾了下express,想找个合适的模版引擎,下面是一些折腾过程的备忘 选择标准 选择一门模版语言时,可能会考虑的几点 语法友好(micro tmpl那种语法真是够了) 支持模版嵌套(子模版的 ...

  8. Objective-C教程备忘单

    终极版本的Objective-C教程备忘单帮助你进行iOS开发. 想开始创建你的第一个iOS应用程序么?那么看一下这篇很棒的教程吧:Create your first iOS 7 Hello Worl ...

  9. HTML5属性备忘单

    在网上闲逛的时候看到了文章,感觉总结的这个html5文章,决定转载过来,在排版的时候也帮助自己重新梳理复习一遍.毕竟学习基础最重要. by zhangxinxu from http://www.zha ...

  10. 工作效率-十五分钟让你快速学习Markdown语法到精通排版实践备忘

    关注「WeiyiGeek」公众号 设为「特别关注」每天带你玩转网络安全运维.应用开发.物联网IOT学习! 希望各位看友[关注.点赞.评论.收藏.投币],助力每一个梦想. 文章目录: 0x00 前言简述 ...

随机推荐

  1. database software runInstaller无法看到全部的rac节点的处理方法

    近期遇到一个问题:rhel5.5下 安装11.2.0.4的rac.GI安装完了没问题. 可是 database software  runInstaller安装时,全部的节点在图形化界面中看不到. 搜 ...

  2. ts demuxer的加入记录

    文件夹 1 初衷 2 ts demux的功能介绍 1 初衷 之前打算给dtplayer加入一些亮点功能,最初的想法是:bt下载播放 + hls支持 bt下载因为以来libtorrent库,尽管搞懂了怎 ...

  3. Archive for the ‘Erlang’ Category 《Erlang编程指南》读后感

    http://timyang.net/category/erlang/ 在云时代,我们需要有更好的能利用多核功能及分布式能力的编程语言,Erlang在这方面具有天生的优势,因此我们始终对它保持强烈关注 ...

  4. 用Canvas画一个刮刮乐

    Canvas 通过 JavaScript 来绘制 2D图形.Canvas 是逐像素进行渲染的.开发者可以通过javascript脚本实现任意绘图.Canvas元素是HTML5的一部分,允许脚本语言动态 ...

  5. sparksql 动态设置schema将rdd转换成dataset/dataframe

    java public class DynamicDemo { private static SparkConf conf = new SparkConf().setAppName("dyn ...

  6. 关于java.lang.NoSuchMethodError: org.springframework.util.ReflectionUtils.makeAccessible

    <span style="font-size:18px;"> java.lang.NoSuchMethodError: org.springframework.util ...

  7. css3中的制作动画小总结

    系列教程 CSS3属性中有关于制作动画的三个属性:Transform,Transition,Animation: Transform 在CSS3中transform主要包括以下几种:旋转rotate. ...

  8. CLR托管内存

    在物理内存中观察CLR托管内存及GC行为   虽然看了一些书,还网络上的一些博文,不过对CLR托管内存细节依然比较模糊.而且因为工作原因总会有很多质疑,想要亲眼看到内存里二进制数据的变化. 所以借助w ...

  9. 关于linux下如何使用svn 客户端

    1 yum install -y subversion (下载svn) 2 svn chekout "你的svn地址" 然后会询问? 我也不知道是嗄意思 , 大体就是权限什么乱七八 ...

  10. Net多线程编程

    Net多线程编程—使用Visual Studio 2012进行调试 1 相关概念 1)栈帧 C语言中,每个栈帧对应着一个未运行完的函数.栈帧中保存了该函数的返回地址和局部变量. 栈帧也叫过程活动记录, ...