1.1:00 — 特性(Attribute)是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签
1.2:02 — 预定于特性、自定义特性
– .Net 框架提供了三种预定义特性:
– AttributeUsage、这个预定义特性描述了如何使用一个自定义特性类。
– Conditional、这个预定义特性标记了一个条件方法,其执行依赖于指定的预处理标识符。
– Obsolete、这个预定义特性标记了不应被使用的程序实体。它可以让您通知编译器丢弃某个特定的目标元素。
特性的详细描述
2.1:00 — 反射指程序可以访问、检测和修改它本身状态或行为的一种能力。
– 程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。
– 反射可以动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。
– System.Reflection 类的 MemberInfo(高级别) 对象需要被初始化,用于发现与类相关的特性(attribute)。
– 遍历类的特性
System.Reflection.MemberInfo info = typeof(MyClass);
object[] attributes = info.GetCustomAttributes(true);
Type type = typeof(Rectangle);
object[] attributes = type.GetCustomAttributes(false);
– 遍历方法特性
System.Reflection.MethodInfo[] m = in type.GetMethods();
Attribute[] = m[0].GetCustomAttributes(true)
将 (DeBugInfo)a 修改为 DeBugInfo dbi = a as DeBugInfo;
原因:
前者是一种强制转换类型,是一种将两个不同类型的值向上或者向下转换因此会报错。后者,通过 object 声明对象,是用了装箱和拆箱的概念,也就是说 object 可以看成是所有类型的父类,因此 object 声明的对象可以转换成任意类型的值。
反射的详细描述
3.1:00 — 属性(Property) 是类(class)、结构(structure)和接口(interface)的命名(named)成员。类或结构中的成员变量或方法称为 域(Field)。属性(Property)是域(Field)的扩展,且可使用相同的语法来访问。它们使用 访问器(accessors) 让私有域的值可被读写或操作。
– 属性(Property)不会确定存储位置。相反,它们具有可读写或计算它们值的 访问器(accessors)。例如,有一个名为 Student 的类,带有 age、name 和 code 的私有域。我们不能在类的范围以外直接访问这些域,但是我们可以拥有访问这些私有域的属性。
属性的详细描述
4.1:00 — 索引器(Indexer) 允许一个对象可以像数组一样被索引。当您为类定义一个索引器时,该类的行为就会像一个 虚拟数组(virtual array) 一样。您可以使用数组访问运算符([ ])来访问该类的实例。
– 可用于自定义类型数组
4.2:重载索引器(Indexer)索引器(Indexer)可被重载。索引器声明的时候也可带有多个参数,且每个参数可以是不同的类型。没有必要让索引器必须是整型的。C# 允许索引器可以是其他类型,例如,字符串类型。
索引器的详细描述
5.1:00 — 委托(Delegate)C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。委托(Delegate)特别用于实现事件和回调方法。所有的委托(Delegate)都派生自 System.Delegate 类。
– 声明委托(Delegate)委托声明决定了可由该委托引用的方法(PS:简单来讲就是限定了在运行时可以对该引用类型变量进行赋值的值类型)。委托可指向一个与其具有相同标签的方法。
public delegate int MyDelegate (string s);
上面的委托可被用于引用任何一个带有一个单一的 string 参数的方法,并返回一个 int 类型变量。
声明委托的语法如下:
delegate <return type> <delegate-name> <parameter list>
– 实例化委托(Delegate)一旦声明了委托类型,委托对象必须使用 new 关键字来创建,且与一个特定的方法有关。当创建委托时,传递到 new 语句的参数就像方法调用一样书写,但是不带有参数。
public delegate void printString(string s);
...
printString ps1 = new printString(WriteToScreen);
printString ps2 = new printString(WriteToFile);
– 委托(Delegate)的用途 -> 实现连续的方法调用
委托的详细描述
6.1:00 — 事件(Event) 基本上说是一个用户操作,如按键、点击、鼠标移动等等,或者是一些提示信息,如系统生成的通知。应用程序需要在事件发生时响应事件。
C# 中使用事件机制实现线程间的通信。
– 通过事件使用委托事件在类中声明且生成,且通过使用同一个类或其他类中的委托与事件处理程序关联。包含事件的类用于发布事件。这被称为 发布器(publisher) 类。其他接受该事件的类被称为 订阅器(subscriber) 类。事件使用 发布-订阅(publisher-subscriber) 模型。
发布器(publisher) 是一个包含事件和委托定义的对象。事件和委托之间的联系也定义在这个对象中。发布器(publisher)类的对象调用这个事件,并通知其他的对象。
订阅器(subscriber) 是一个接受事件并提供事件处理程序的对象。在发布器(publisher)类中的委托调用订阅器(subscriber)类中的方法(事件处理程序)。
– 声明事件(Event)在类的内部声明事件,首先必须声明该事件的委托类型。
public delegate void BoilerLogHandler(string status);
然后,声明事件本身,使用 event 关键字:
// 基于上面的委托定义事件
public event BoilerLogHandler BoilerEventLog;
上面的代码定义了一个名为 BoilerLogHandler 的委托和一个名为 BoilerEventLog 的事件,该事件在生成的时候会调用委托。
事件的详细描述
7.1:06 — 集合(Collection)类是专门用于数据存储和检索的类。这些类提供了对栈(stack)、队列(queue)、列表(list)和哈希表(hash table)的支持。大多数集合类实现了相同的接口。集合(Collection)类服务于不同的目的,如为元素动态分配内存,基于索引访问列表项等等。这些类创建 Object 类的对象的集合。
在 C# 中,Object 类是所有数据类型的基类。
集合的详细描述
8.1:00 — 泛型(Generic) 允许您延迟编写类或方法中的编程元素的数据类型(PS:例如变量类型)的规范,直到实际在程序中使用它的时候。换句话说,泛型允许您编写一个可以与任何数据类型一起工作的类或方法。您可以通过数据类型的替代参数编写类或方法的规范。当编译器遇到类的构造函数或方法的函数调用时,它会生成代码来处理指定的数据类型。
8.2:05 — 泛型(Generic)的特性、使用泛型是一种增强程序功能的技术,具体表现在以下几个方面:
– 它有助于您最大限度地重用代码、保护类型的安全以及提高性能。
– 可以创建泛型集合类。.NET 框架类库在 System.Collections.Generic 命名空间中包含了一些新的泛型集合类、 可以使用这些泛型集合类来替代 System.Collections 中的集合类。
– 可以创建自己的泛型接口、泛型类、泛型方法、泛型事件和泛型委托。
– 可以对泛型类进行约束以访问特定数据类型的方法。
– 关于泛型数据类型中使用的类型的信息可在运行时通过使用反射获取。
泛型的详细描述
9.1:00 — 委托是用于引用与其具有相同标签的方法。换句话说,可以使用委托对象调用可由委托引用的方法。匿名方法(Anonymous methods) 提供了一种传递代码块作为委托参数的技术。匿名方法是没有名称只有主体的方法。在匿名方法中可以不指定返回类型,它是从方法主体内的 return 语句推断的。
– 编写匿名方法的语法,匿名方法是通过使用 delegate 关键字创建委托实例来声明的。
delegate void NumberChanger(int n);
...
NumberChanger nc = delegate(int x)
{
Console.WriteLine("Anonymous Method: {0}", x);
};
代码块 Console.WriteLine(“Anonymous Method: {0}”, x); 是匿名方法的主体。
委托可以通过匿名方法调用,也可以通过命名方法调用,即,通过向委托对象传递方法参数。
10.1:00 — 当一个代码块使用 unsafe 修饰符标记时,C# 允许在函数中使用指针变量。不安全代码或非托管代码是指使用了指针变量的代码块。
– 指针变量、指针 是值为另一个变量的地址的变量,即,内存位置的直接地址。就像其他变量或常量,您必须在使用指针存储其他变量地址之前声明指针。
指针变量声明的一般形式为:
type* var-name;
不安全代码的详细描述
11.1:00 — 线程 被定义为程序的执行路径。每个线程都定义了一个独特的控制流。如果您的应用程序涉及到复杂的和耗时的操作,那么设置不同的线程执行路径往往是有益的,每个线程执行特定的工作。线程是轻量级进程。一个使用线程的常见实例是现代操作系统中并行编程的实现。使用线程节省了 CPU 周期的浪费,同时提高了应用程序的效率。
11.2:04 — 线程生命周期状态、线程生命周期开始于 System.Threading.Thread 类的对象被创建时,结束于线程被终止或完成执行时。
– 未启动状态:当线程实例被创建但 Start 方法未被调用时的状况。
– 就绪状态:当线程准备好运行并等待 CPU 周期时的状况。
– 不可运行状态:下面的几种情况下线程是不可运行的:
已经调用 Sleep 方法
已经调用 Wait 方法
通过 I/O 操作阻塞
– 死亡状态:当线程已完成执行或已中止时的状况。
11.3:00 — 主线程、在 C# 中,System.Threading.Thread 类用于线程的工作。它允许创建并访问多线程应用程序中的单个线程。进程中第一个被执行的线程称为主线程。
多线程的描述
12.1:00 — 语言集成查询( LINQ )
– 大多数应用都是以数据为中心的,然而大多数的数据仓库是关系型数据库。这些年,设计者和开发者设计了基于对象模型的应用程序。
– 对象来负责连接访问数据的组件——称为数据访问层( DAL )。这里我们需要考虑三点:
– 一个应用程序所需要的所有数据可以不存储在一个资源中。这个资源可以是关系型数据库、业务对象、XML文件或者一个WEB服务器。
– 访问内存中的对象要比访问数据库、XML文件中的数据更简单,更廉价。
– 被访问到的数据不是直接使用的,而是被转存、排序、分组、修改等。
因此如果存在只是用几行代码就能实现轻易整合各种各样的数据——可以整合来自不同源的数据,并且能够执行基本的数据操作的工具,那将非常有用。
– 语言集成查询( LINQ )就是上述那样的一种工具。 LINQ 是 .NET Framework 3.5 的一个扩展集并且它的管理语言使查询更类似于是一种对象。它定义了一种通用的语法和程序模型,使我们可以使用一种惯用的语法完成查找不同类型的数据。
– 相关操作像查找、工程、链接、分组、分区、集合操作等可以在 LINQ 中使用,并且在 .NET Framework 3.5 中的 C# 和 VB 编译器支持 LINQ 的语法,这就使得它可以通过配置数据来存储,而不需要求助于 ADO.NET。
var data = from c in dataContext.Customers
where c.Country == "Spain"
select c;
其中:
from关键字逻辑上依次通过每个集合。
包含关键字where的表达式会比较集合中的每个对象。
select声明会选择被比较出的对象加入到列表中并返回。
关键字var用于变量声明。因为返回对象的准确类型不明确,它表明信息需要被动态的推测。
– LINQ 查询语句可以应用在任何继承于 IEnumerable 的有数据支撑的类,这里 T 可以是任何一个数据类型,例如 List< Book >。
public class Books
{
public string ID {get; set;}
public string Title { get; set; }
public decimal Price { get; set; }
public DateTime DateOfRelease { get; set; }
public static List<Books> GetBooks()
{
List<Books> list = new List<Books>();
list.Add(new Books { ID = "001",
Title = "Programming in C#",
Price = 634.76m,
DateOfRelease = Convert.ToDateTime("2010-02-05") });
list.Add(new Books { ID = "002",
Title = "Learn Jave in 30 days",
Price = 250.76m,
DateOfRelease = Convert.ToDateTime("2011-08-15") });
list.Add(new Books { ID = "003",
Title = "Programming in ASP.Net 4.0",
Price = 700.00m,
DateOfRelease = Convert.ToDateTime("2011-02-05") });
list.Add(new Books { ID = "004",
Title = "VB.Net Made Easy",
Price = 500.99m,
DateOfRelease = Convert.ToDateTime("2011-12-31") });
list.Add(new Books { ID = "005",
Title = "Programming in C",
Price = 314.76m,
DateOfRelease = Convert.ToDateTime("2010-02-05") });
list.Add(new Books { ID = "006",
Title = "Programming in C++",
Price = 456.76m,
DateOfRelease = Convert.ToDateTime("2010-02-05") });
list.Add(new Books { ID = "007",
Title = "Datebase Developement",
Price = 1000.76m,
DateOfRelease = Convert.ToDateTime("2010-02-05") });
return list;
}
}
在 web 网页中使用这个类要有简单的标签控制,来显示书的标题。Page_Load 方法创建了一个书的列表并且通过使用 LINQ 查询返回标题:
public partial class simplequery : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
List<Books> books = Books.GetBooks();
var booktitles = from b in books select b.Title;
foreach (var title in booktitles)
lblbooks.Text += String.Format("{0}
", title);
}
}
Linq的详细描述
13.1:00 — lambda表达式是一个未命名的方法
– Lambda 表达式语法:(parameters) => expression
– Lambda表达式在委托中的使用
delegate int Converter (int i);
//我们可以写和调用匿名方法如下:
Converter sqr = delegate (int x) {return x * x;};
Console.WriteLine (sqr(3)); // 9
//第一行在语义上等同于以下lambda表达式:
Converter sqr = (int x) => {return x * x;};
//或者简单为:
Converter sqr = x => x * x;
//匿名方法以与lambda表达式相同的方式捕获外部变量。
lambda的详细描述