标题：C#.net
概述
C#是一个语言，.net是一个平台，上面支持用C#或者VBdotNet写代码。 
另外，C#不但可以开发基于.net的应用程序，也可以开发基于WinForm的程序，这就是区别。
若是单纯以概念来说，你可以把.net当做一个工作平台一般，它是一个开发环境的基底，提供你开发Windows、Web、Mobile、XML...等应用程式一个共通的平台，若是要了解深一点，则再去了解其运作的相关机制那是有助于你利用它来开发.C#和.NET主要是应用在网际网路的。起源C#（读做C-sharp）编程语言是由微软公司的Anders Hejlsberg和 Scott Willamette领导的开发小组专门为.NET平台设计的语言，它可以使程序员移植到.NET上。这种移植对于广大的程序员来说是比较容易的，因为C#从C，C++和Java发展而来，它采用了这三种语言最优秀的特点，并加入了它自己的特性。C#是事件的驱动的，完全面向对象的可视化编程语言，我们可以使用集成开发环境来编写C#程序。使用IDE，程序员可以方便的建立，运行，测试和调试C#程序，这就将开发一个可用程序的时间减少到不用IDE开发时所用时间的一小部分。使用IDE迅速建立一个应用程序的过程称为快速反映开发。简介. NET 是 Microsoft 的 XML Web 服务平台。不论操作系统或编程语言有何差别，XML Web 服务能使应用程序在 Internet 上传输和共享数据。
Microsoft® .NET 平台包含广泛的产品系列，它们都是基于 XML 和 Internet 行业标准构建，提供从开发、管理、使用到体验 XML Web 服务的每一方面。XML Web 服务将成为您今天正在使用的 Microsoft 的应用程序、工具和服务器的一部分 — 并且将要打造出全新的产品以满足您所有业务需求。
更具体地说，Microsoft 正在五个方面创建 .NET 平台，即工具、服务器、XML Web 服务、客户端和 .NET 体验。
C#2.0新特性
1、 泛型在我看来，泛型就是通过将数据类型参数化从而实现了代码的更为灵活的复用，泛型的出现使得C#能够使用同一段代码来操作多种数据类型。泛型无疑是C#2.0最重大的改进，它的出现赋予了C#代码更强的类型安全，更好的复用，更高的效率和更清晰的约束。2、 匿名方法匿名方法允许我们将代码直接与委托实例相关联，使委托实例化工作更加直观和方便。在我看来，这只是C#又多了一种语法格式而已，不再像以前必须将方法名传给委托实例，而是又多了一种选择。3、 迭代器迭代器允许我们更加方便的编写用于foreach语句的类型。在我看来，迭代器的出现只不过是改进了1.0中不便的可用foreach语句类型的编写限制，简化了一些接口。4、 局部类型局部类型允许我们将一个类的代码分别写在不同的cs文件中。最典型的应用就是使用VS2005创建Form文件时，VS会自动将系统生成的代码与用户代码分开。局部类型通过partial关键字来声明。5、 空属类型空属类型是一种像int，一样可以为空的变量类型。本质上是一种泛型的应用，是System .Nullable<>的一种类型实例化。6、 静态类：静态类是只用于包含静态成员的类型，它既不能实例化，亦不能被继承。
C#3.0新特性
1：隐式类型化本地变量这个特性非常简单，有些JavaScript的影子，我们可以统一使用使用"var"关键字来声明局部变量，而不再需要指明变量的确切类型了，变量的确切类型可通过声明变量时的初始值推断出来。这样一来，可以大大简化我们声明局部变量的工作量了，下面是一个例子： 
class LocalVariables : AppRunner.AbstractApplication 
{ 
public override void Run() 
{ 
var intValue = 5; 
var stringValue = "This is a string"; 
var customClass = new LocalVariables(); 
var intArray = new int[3] { 1, 2, 3 }; 
foreach (var value in intArray) 
Console.WriteLine(value); 
} 
}
上面的代码将被解析成： 
class LocalVariables : AppRunner.AbstractApplication 
{ 
public override void Run() 
{ 
int intValue = 5; 
string stringValue = "This is a string"; 
LocalVariables customClass = new LocalVariables(); 
int[] intArray = new int[3]; 
foreach (int value in intArray) 
Console.WriteLine(value); 
} 
}
要特别注意的是，由于变量的类型是通过变量初始值推断而来的，所以在声明变量的同时必需为变量指定初始值。并且，变量并不是没有类型的，变量一旦初始化之后，类型就确定下来了，以后就只能存储某种类型的值了，比如上面的stringValue的类型经推断为string，所以该变量就只能保存string类型的值了。2：匿名类型有些时候我们需要临时保存一些运算的中间结果，特别是当这些中间结果是由多个部份组成时，我们常常会去声明一个新的类型，以方便保存这些中间结果。表面上看起来这很正常，而细想之后就会发现，这个新类型只服务于这个函数，其它地方都不会再使用它了，就为这一个函数而去定义一个新的类型，确实有些麻烦。 
现在，C#3.0中的匿名类型特性就可以很好的解决上面提到的问题，通过匿名类型，我们可以简单使用new { 属性名1=值1, 属性名2=值2, ..... , 属性名n=值n }的形式直接在函数中创建新的类型，看下面这个例子： 
class AnonymousType : AppRunner.AbstractApplication 
{ 
public override void Run() 
{ 
var anonymousType1 = new { 
CardNumber = "10001", Name = "van’s", Sex = true 
}; 
Console.WriteLine(anonymousType1.CardNumber); 
Console.WriteLine
var anonymousType2 = new { 
CardNumber = "10002", Name = "martin", Sex = true 
}; 
anonymousType2 = anonymousType1; 
} 
}
在新类型中只能有字段成员，而且这些字段的类型也是通过初值的类型推断出来的。如果在声明新的匿名类型时，新类型的字段名、顺序以及初始值的类型是一致的，那么将会产生相同的匿名类型，所以上例中anonymousType1和anonymousType2的类型是相同的，自然能进行anonymousType2=anonymousType1的赋值。3：隐式类型化数组这个特性是对隐式类型化本地变量的扩展，有了这个特性，将使我们创建数组的工作变得简单。我们可以直接使用"new[]"关键字来声明数组，后面跟上数组的初始值列表。在这里，我们并没有直接指定数组的类型，数组的类型是由初始化列表推断出来的。 
class AnonymousTypeArray : AppRunner.AbstractApplication 
{ 
public override void Run() 
{ 
var intArray = new[] { 1, 2, 3, 4, 5 }; 
var doubleArray = new[] { 3.14, 1.414 }; 
var anonymousTypeArray = new[] { 
new { Name="van’s", Sex=false, Arg=22 }, 
new { Name="martin", Sex=true, Arg=23 } 
}; 
Console.WriteLine(intArray); 
Console.WriteLine(doubleArray); 
Console.WriteLine(anonymousTypeArray[0].Name); 
} 
}
上面的代码中，anonymousTypeArray变量的声明同时运用了隐式类型化数组和匿名类型两种特性，首先创建匿名类型，然后再初始值列表，推断出数组的确切类型。4：对象构造者我们在声明数组时，可以同时对其进行初始化，这样就省去了很多麻烦，但是在创建类的对象时，这招可就不灵了，我们要么调用该类的构造函数完成对象的初始化，要么就手工进行初始化。这两种方法都不太方便，使用构造函数来对对象进行初始化时，我们为了某种灵活性，可能需要编写构造函数的多个重载版本，实在是麻烦。 
C#3.0中加入的对象构造者特性，使得对象的初始化工作变得格外简单，我们可以采用类似于数组初始化的方式来初始化类的对象，方法就是直接在创建类对象的表达式后面跟上类成员的初始化代码。具体示例如下： 
class Point 
{ 
public int X { get; set; } 
public int Y { get; set; } 
public override string ToString() 
{ 
return "(" + X.ToString() + ", " + Y.ToString() + ")"; 
} 
} 
class Rectangle 
{ 
public Point P1 { get; set; } 
public Point P2 { get; set; } 
public Rectangle() 
{ 
P1 = new Point(); 
P2 = new Point(); 
} 
public override string ToString() 
{ 
return "P1: " + P1 + ", P2: " + P2; 
} 
} 
class ObjectBuilder : AppRunner.AbstractApplication 
{ 
public override void Run() 
{ 
Point thePoint = new Point() { X = 1, Y = 2 }; 
Console.WriteLine("Point(X, Y) = ", thePoint); 
Rectangle theRectangle = new Rectangle() { 
P1 = { X = 1, Y = 1 }, P2 = { X = 100, Y = 200 } 
}; 
Console.WriteLine(theRectangle); 
} 
}
我们在定义Point类的X和Y属性时，只须写上该属性的get和set访问器声明，C#编译器会自动为我们生成默认的get和set操作代码，当我们需要定义简单属性时，这个特性非常有用。 
我们以new Point() { X = 1, Y = 2 }语句，轻松的完成了对Point类的初始化工作。在创建类的对象时，我们可以按照需要去初始化类的对象，只要在类的创建表达式后跟上要初始化属性的列表即可，且可以只对需要初始化的属性赋初值，而无需把所有属性的初始值都写上去。 
在theRectangle对象的初始化表达式中，我们首先对P1属性进行初始化，然而P1属性也是一个自定义的类型，所以P1属性的初始化是另一个类型(Point)的初始化表达式，我们可以这样的方式来对更加复杂的类型进行初始化。 
上篇文章中介绍了C# 3.0中比较简单的四个特性，分别是隐式类型化本地变量、匿名类型、隐式类型化数组，以及对象构造者，下面我将对C# 3.0中的较复杂，同时也是非常强大的几个特性进行介绍，供大家快速浏览。5：集合构造者我们可以在声明数组的同时，为其指定初始值，方法是直接在数组声明的后面跟上初始值列表。这样就使数组的初始化工作变得简单，而对于我们自己创建的集合类型，就无法享受到与普通数组一样的待遇了，我们无法在创建自定义集合对象的同时，使用数组的初始化语法为其指定初始值。
C# 3.0中加入的集合构造者特性，可使我们享受到与普通数组一样的待遇，从而在创建集合对象的同时为其指定初始值。为了做到这一点，我们需要让我们的集合实现ICollection<T>接口，在这个接口中，完成初始化操作的关键在于Add函数，当我使用初始化语法为集合指定初始值时，C#编译器将自动调用ICollection<T>中的Add函数将初始列表中的所有元素加入到集合中，以完成集合的初始化操作。使用示例如下：
class CollectionInitializer : AppRunner.AbstractApplication
{
class StringCollection : ICollection<string>
{
public void Add(string item)
{
Console.WriteLine(item);
}
// Other ICollection<T> Members
}
public override void Run()
{
StringCollection strings = new StringCollection() { "Van's", "Brog", "Vicky" };
}
}
在这个示例中，编译器会自动为strings对象调用Add方法，以将初始值列表中的所有元素加入到集合中，这里我们只是简单将初始值列表中的元素输出到控制台。6：Lambda表达式C# 2.0中加入的匿名代理，简化了我们编写事件处理函数的工作，使我们不再需要单独声明一个函数来与事件绑定，只需要使用delegate关键字在线编写事件处理代码。
而C# 3.0则更进一步，通过Lambda表达式，我们可以一种更为简洁方式编写事件处理代码，新的Lambda事件处理代码看上去就像一个计算表达式，它使用"=>"符号来连接事件参数和事件处理代码。我可以这样写：SomeEvent += 事件参数 => 事件处理代码;下面是完整的示例：
delegate T AddDelegate<T>(T a, T b);
class LambdaExpression : AppRunner.AbstractApplication
{
public static event EventHandler MyEvent;
public override void Run()
{
MyEvent += delegate(object s, EventArgs e)
{
Console.WriteLine(s);
};
MyEvent += (s, e) => { Console.WriteLine(s); };
MyEvent(this, null);
AddDelegate<string> add = (a, b) => a + b;
Console.WriteLine(add("Lambda", "Expression"));
}
}
在上面的例子中，分别使用了匿名代理和Lambda表达式来实现同样的功能，可以明显看出Lambda表达式的实现更为简洁。我们在使用Lambda表达式编写事件处理代码时，无需指明事件参数的类型，且返回值就是最后一条语句的执行结果。7：扩展方法当我们需要对已有类的功能进行扩展时，我们通常会想到继承，继承已有类，然后为其加入新的行为。而C# 3.0中加入的扩展方法特性，则提供了另一种实现功能扩展的方式，我们可以在不使用继承的前提下实现对已有类本身的扩展，这种方法并不会产生新的类型，而是采用向已有类中加入新方法的方式来完成功能扩展。
在对已有类进行扩展时，我们需将所有扩展方法都写在一个静态类中，这个静态类就相当于存放扩展方法的容器，所有的扩展方法都可以写在这里面。而且扩展方法采用一种全新的声明方式：public static 返回类型 扩展方法名(this 要扩展的类型 sourceObj [,扩展方法参数列表])，与普通方法声明方式不同，扩展方法的第一个参数以this关键字开始，后跟被扩展的类型名，然后才是真正的参数列表。下面是使用示例：
static class Extensions
{
public static int ToInt32(this string source)
{
return Int32.Parse(source);
}
public static T[] Slice<T>(this T[] source, int index, int count)
{
if (index < 0 || count < 0 || index + count > source.Length)
{
throw new ArgumentException();
}
T[] result = new T[count];
Array.Copy(source, index, result, 0, count); 
return result;
}
}
class ExtensionMethods : AppRunner.AbstractApplication
{
public override void Run()
{
string number = "123";
Console.WriteLine(number.ToInt32());
int[] intArray = new int[] { 1, 2, 3 };
intArray = intArray.Slice(1, 2);
foreach (var i in intArray)
Console.WriteLine(i);
}
}
在上面的示例中，静态的Extensions类中有两个扩展方法，第一个方法是对string类的扩展，它为string类加入了名为ToInt32的方法，该方法没有参数，并返回一个int类型的值，它将完成数字字符向整数的转换。有了这个扩展方法之后，就可对任意string类的对象调用ToInt32方法了，该方法就像其本身定义的一样。
第二个扩展方法是一个范型方法，它是对所有数组类型的扩展，该方法完成数组的切片操作。
C# 3.0中的Linq表达式，就是大量运用扩展方法来实现数据查询的。8：Linq查询表达式C# 3.0中加入的最为复杂的特性就是Linq查询表达式了，这使我们可直接采用类似于SQL的语法对集合进行查询，这就使我们可以享受到关系数据查询的强大功能。
Linq查询表达式是建立在多种C# 3.0的新特性之上的，这也是我为什么最后才介绍Linq的原因。下面看一个例子：
class LinqExpression : AppRunner.AbstractApplication
{
public override void Run()
{
// 定义匿名数组persons, 并为其赋初值
var persons = new[] {
new { Name="Van's", Sex=false, Age=22 },
new { Name="Martin", Sex=true, Age=30 },
new { Name="Jerry", Sex=false, Age=24 },
new { Name="Brog", Sex=false, Age=25 },
new { Name="Vicky", Sex=true, Age=20 }
};
/*
执行简单Linq查询
检索所有年龄在24岁以内的人
查询结果放在results变量中
results变量的类型与数组persons相同 
*/
var results = from p in persons
where p.Age <= 24
select p;
foreach (var person in results)
{
Console.WriteLine
Console.WriteLine();
// 定义匿名数组customers, 并为其赋初值
// 该数组是匿名类型的
var customers = new[] {
new {
Name="Van's", City="China", Orders=new[] {
new {
OrderNo=0,
OrderName="C# Programming Language(Second Edition)",
OrderDate=new DateTime(2007,9, 5)
},
new {
OrderNo=1,
OrderName="Head First Design Patterns(Chinese Edition)",
OrderDate=new DateTime(2007,9,15)
},
new {
OrderNo=2,
OrderName=Unleashed 2.0(Chinese Edition)",
OrderDate=new DateTime(2007,09,18)
},
new {
OrderNo=3,
OrderName="The C++ Programming Langauge(Special Edition)",
OrderDate=new DateTime(2002, 9, 20)
}
}
},
new {
Name="Brog", City="China", Orders=new[] {
new {
OrderNo=0,
OrderName="C# Programming Language(Second Edition)",
OrderDate=new DateTime(2007, 9, 15)
}
}
},
new {
Name="Vicky", City="London", Orders=new[] {
new { OrderNo=0,
OrderName="C++ Programming Language(Special Edition)",
OrderDate=new DateTime(2007, 9, 20)
}
}
}
};
/*
执行多重Linq查询
检索所在城市为中国, 且订单日期为2007年以后的所有记录
查询结果是一个匿名类型的数组
其中包含客户名, 订单号, 订单日期, 订单名四个字段
*/
var someCustomers = from c in customers
where c.City == "China"
from o in c.Orders
where o.OrderDate.Year >= 2007
select new o.OrderNo, o.OrderDate, o.OrderName };
foreach (var customer in someCustomers)
{
Console.WriteLine " + customer.OrderName + ", " +
customer.OrderDate.ToString("D")
);
}
}
}
从上面的例子中，我们可以看到Linq查询的强大特性，它允许我们进行简单查询，或者进行更为复杂的多重连接查询。且查询的结果还可以是自定义的匿名类型。
控件
C#提供了很多控件用于开发应用程序。
C#标准控件根据其应用环境分为两类：
Windows Form控件：主要用于Windows应用程序的开发。所有的Windows控件都是从Control类中派生来的，该类包含了所有用户界面的Windows Form组件，其中也包括Form类。Control类中包括了很多位所有控件所共享的属性、时间和方法。它包含复选框、文本框、按钮、标签、图像列表等。
Web窗体控件：主要用于Web应用程序的开发。它是专门针对Asp .NET Web窗体设计的服务器控件。Web窗体控件包含在命名空间System.Web.UI.WebControls中，当用户使用Visual Studio创建Web窗体页面时，会自动在后台代码文件中添加引用该命名空间的Using语句。
.NET Compact Framework 提供了可以满足大多数设备项目需要的Windows Form控件。若要使用这些控件没有的功能，可以从公共控件派生您自己的自定义控件。可以通过定义从 Control 类或从程序集中的现有 UserControl 继承的公共类型创建自定义控件。
最简单的控件自定义是重写公共控件的方法。例如，可以重写 TextBox 控件的 OnKeyPress 继承方法，提供将输入限制为数字字符的代码。
如若觉得自定义控件过于浪费时间和复杂，也可以从受信任的来源下载控件，并通过添加引用来导入自定义控件。支持这些自定义的.NET的控件有：ComponentOne Studio, Spread，ActiveReports、MultiRow等。[1]