泛型

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. Maven学习笔记(六):生命周期与插件

    何为生命周期:      Maven的生命周期就是为了对全部的构建过程进行抽象和统一.Maven从大量项目和构建工具中学习和反思,然后总结了一套高度完好的.易扩展的生命周期.这个生命周期包括了项目的清 ...

  2. [GeekBand] 设计模式之观察者模式学习笔记

    本文参考文献::GeekBand课堂内容,授课老师:李建忠 :网络资料: http://blog.csdn.net/hguisu/article/details/7556625 本文仅作为自己的学习笔 ...

  3. Winfrom 重新登录

    private void ReLogin_Click(object sender, EventArgs e) { ///实例化一个进程 Process process = new Process(); ...

  4. 【14.94%】【codeforces 611E】New Year and Three Musketeers

    time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...

  5. 手推机器学习公式(一) —— BP 反向传播算法

    方便起见,本文仅以三层的神经网络举例. f(⋅):表示激励函数 xi:表示输入层: yj:表示中间的隐层: yj=f(netj) netj=∑i=0nvijxi ok:表示输出层,dk 则表示期望输出 ...

  6. 使用JScript编译指定目录下所有工程

    作者:朱金灿 来源:http://blog.csdn.net/clever101 我遇到这样一个问题:在一个插件工程目录下的插件工程越来越多,因此通过建一个解决方案然后把新增加的工程逐个添加进解决方案 ...

  7. Solid-state storage management

    Solid-state storage management for a system, the management including establishing, externally to a ...

  8. 【cocos2d-js官方文档】五、Cocos2d-JS v3.0的新Action API

    新增action中的方法 曾经,当我们须要反复一个action的时候,我们须要: sprite.runAction(cc.Repeat.create(action, 2)); 上面代码中创建了一个新的 ...

  9. 记一次由于缓存导致的bug

    bug描述 有一张数据库表存储的是 值日员工信息,有时候可能一次性录入1个月的数据.有时候也可能隔了很多天没有录入数据,也就是说这个录数据不是很规律. bug现象:测试人员发现,网站上三亚地区能正常显 ...

  10. 3 WCF一些基础铺垫

    1首先上一张wcf通讯图 a.Proxy代理部分底层调用的是 xxxxClient=> ChannelFactory=>IInpuChannel/IOutChannel... b.Tran ...