C# 1

1.转移序列 @ 的用法:
  "C://TEMP//Mydir//Myfile.doc"
  应用@后:
  @"C:/TEMP/Mydir/Myfile.doc"
  唯一的例外就是 " ,必须用/"指定。

2.在switch中,C#只能执行一个case语句。不能像C++那样,在没遇到break之前,可以一次执行多个。

3.溢出检查环境:
  checked(expression) 检查是否溢出
desVar = checked((byte)sourceVar);
  unchecked(expression) 不检查是否溢出
  或者在VS中右击Solution explorer窗口中的项目,选择 properties,点击左边的build。
  点击advanced, 勾择 check for arithmetic overflow/underflow。默认是不检查的。

4.Convert.ToInt16(val);将val转换为INT16类型。
  Convert.*在System名称空间中,不是C#本身。并且他们总是进行溢出检查,所以Checked和unchecked关键字没用。

5.枚举类型转换
  枚举值转成字符串:ToString()
  字符串转成枚举值:(enumerationType)Enum.Parse(typeof(enumerationType), enumerationValueString);
  string myString = "north";
  orientation myDirection = (orientation)Enum.Parse(typeof(orientation), myString);

6.数组的声明
  int[] val = {1,2,3,4};
  int[,] val = {{1,2,3,4},{4,5,6,7},{5,6,7,1}};  声明了一个三行四列的二维数组。
  int[,,]声明三维数组。另一种声明方式:int[,,] val =new int[2,2,4];
  多维数组,可称为矩形数组,因为每一行的元素个数都相同。

  数组的数组,变长数组。
  int[][] = {new int[] {1},
    new int[] {1,2},
    new int[] {1,3,4}};
7.字符串处理
  string类型的变量可以看作是Char变量的“只读”数组,如下:
  string mystring = "A string";
  char myChar = myString[1];
 
  获得一个可写char数组的方法,如下:
  string myString = "A string";
  char[] myChars = myString.ToCharArray();

  «string».ToLower() & «string».ToUpper() 用来转换大小写。
  «string».Trim() & «string».TrimStart() & «string».TrimEnd()用来消除字符串中的空格。
  «string».PadLeft()&«string».PadRight():
  myString = "Aligned";   
  myString = myString.PadLeft(10); 在左边加3个空格,凑成10个字符
  myString = myString.padLeft(10,'-');在左边加3个“-”,凑成10个字符

  Split()方法
  string myString = "This is a test";
char[] separator = {' '};  如果有多个条件可以再次输入,如果遇到“a”分开,可以char[] separator = {' ','a'};
string[] myWords;
myWords = myString.Split(seperator);
foreach(string word in myWords)
{
 Console.WriteLine("{0}",word);
}
Console.ReadKey();
运行结果:
This
is
a
test
得到的每个单词没有空格。在使用split时,删除了分隔符。

8.C#参数数组,用params关键字定义
  如果有多个参数,这个参数必须是函数定义中的最后一个参数。实例如下:
static int SumVals(params int[] vals)
{
 int sum = 0;
 foreach(int val in vals)
  {
    sum+=val;
  }
 return sum;
}
调用方式:SumVals(1,5,2,9);
       
9.ref & out作函数参数。如:foo(ref int i) & foo(out int i)
ref 使用前“必须赋值”,离开函数时,可以修改也可以不修改。所以,ref 的参数不能声明为const。
   在调用函数是时也要加ref,如:foo(ref myNumber); ref是函数签名的一部分。
out 使用前不用赋值(赋值也没用,会被清空),离开函数时,必须被重新赋值。否则,会报错。
   调用方法参考ref

10. 委托 delegate
    委托使用三部曲:
    1. 声明
      delegate int ProcessDelegate(int param1, int param2);
     2. 委托变量
     ProcessDelegate Process;
     3. 绑定
     mutiply(int i, int j);
     Process = new ProcessDelegate(mutiply);
     4. 调用
     int result = Process(2,3);

11. IDisposable接口
     用于控制释放所示用的资源。

     支持IDisposable接口的对象必须实现其Dispose()方法。

    
    使用using关键字可以优化使用这个方法的结构,如:

    ClassName VariableName = new ClassName();

    ....

    using(VariableName)

    {
        ......

    }

    或者

    using(ClassName VariableName = new ClassName())

    {
        ......

    }


    这样,在using代码块中使用VariableName,并在代码块末尾自动删除(调用Dispose())。

   

12. public pravite protected
    protected派生类可以访问,外部代码无法访问。

13. 虚拟、抽象、重写 (virtual & abstract & override «& extern» )
     ·i  抽象类可以有非抽象成员。并且抽象类的派生类可以为抽象类,且不用实现所有的抽象成员。非抽象派生类必须实现所有的抽象成员。
     ·ii 隐藏 与 重写
     重写虚方法的时候,会覆盖基类的原方法
     public class MyBaseClass
     {
            public virtual void DoSomething()
       { //Base Implementation.
            Console.WriteLine("Base imp");
       }
     }
 
    public class MyDerivedClass:MyBaseClass
     {
       public override void DoSomething()
       {    //Derived class implementation
            Console.WriteLine("Derived imp");
       }
     }
 
 当 MyDerivedClass myObj = new MyDerivedClass();
    MyBaseClass myBaseObj;
    MyBaseObj = myObj;
             myBaseObj.DoSomething();
         结果如下:
         Derived imp
--------------------------------------------
         隐藏基类方法时,仍然可以通过基类访问。也就是说,基类的方法被覆盖了。 
         可以用new关键字显示声明。也可以不用,隐式声明隐藏,但会显示warning。
 
            public class MyBaseClass   
            {
                public virtual void DoSomething()
                { //Base Implementation.
                    Console.WriteLine("Base imp");
                }
            }
 
         public class MyDerivedClass:MyBaseClass
         {
              new public void DoSomething()
              {
                    Console.WriteLine("Derived imp");
              }
         }
            结果如下:
            Base imp       
---------------------------------------------
        在派生类中,调用重写或隐藏的基类方法,base关键字。
        public class MyBaseClass
        {
             public virtual void DoSomething()
             {
             // Base implementation
             }
        }
        public class MyDerivedClass:MyBaseClass
        {
             public override void DoSomething()
             {   
                // Derived class implementation, extends base class implementation.
                   base.DoSomethig();
               // More derived class implementation
             }
       }
        注意:base使用的是对象实例,所以不能再静态成员中使用。
        this 关键字
        用法同上,该关键字引用对象实例。

14. 对象的包含关系
     用一个成员字段包含对象实例,就可以实现包含关系。

   


15. 创建事件(简单的例子)
MnewButton.Text = "New Button"; // 初始化属性
newButton.Click += new EventHandler(newButton_Click); // 绑定事件处理程序
        ......
private void newButton_Click(object sender, System.EventArgs e){....;};

16. internal 声明的类只能在当前项目中使用。P166

17. 构造函数的执行序列
    ·i public class MyBaseClass
{
  public MyBaseClass(){}
  public MyBaseClass(int i){}
}
-----------------
public class MyDerivedClass: MyBaseClass
{
  public MyDerivedClass()
  public MyDerivedClass(int i)
  public MyDerivedClass(int i, int j)
}
-------------------
  当MyDerivedClass myObj = new MyDerivedClass()时,System.Object.object()-»MyBaseClass.MyBaseClass()-»MyDerivedClass.MyDerivedClass()
当MyDerivedClass myObj = new MyDerivedClass(4)时,System.Object.object()-»MyBaseClass.MyBaseClass()-»MyDerivedClass.MyDerivedClass(4)
当MyDerivedClass myObj = new MyDerivedClass(4,8)时,System.Object.object()-»MyBaseClass.MyBaseClass()-»MyDerivedClass.MyDerivedClass(4,8)
    ·ii base关键字,如果
public class MyDerivedClass: MyBaseClass
{
  ........
  public MyDerivedClass(int i, int j):base(i)
}
那么,当MyDerivedClass myObj = new MyDerivedClass(4,8)时,System.Object.object()-»MyBaseClass.MyBaseClass(4)-»MyDerivedClass.MyDerivedClass(4,8)
public class MyDerivedClass: MyBaseClass
{
  ........
  public MyDerivedClass():base(5)
}
那么,当MyDerivedClass myObj = new MyDerivedClass()时,System.Object.object()-»MyBaseClass.MyBaseClass(i)-»MyDerivedClass.MyDerivedClass(4,8)
    ·iii this关键字,构造函数初始化器
public class MyDerivedClass: MyBaseClass
{
  public MyDerivedClass():this(5,6)
  ........
  public MyDerivedClass(int i, int j):base(i)
}
当MyDerivedClass myObj = new MyDerivedClass()时, System.Object.Object() -» MyBaseClass.MyBaseClass(int i) -» MyDerivedClass.MyDerivedClass(int i ,int j) -» MyDerivedClass.MyDerivedClass()

18. 类库项目
    类库项目没有程序入口点,所以,可以建一个新的应用程序(比如控制台程序),在引用(References)中添加引用(添加编译的类库项目-*.DLL)。

19. 接口
    在实现接口的类中,可以用关键字virtual 或 abstract来执行接口成员,但不能使用static 或 const。
    另外,接口成员还可以在基类中实现,如下:
   
    public interface IMyInterface
    {
       void DoSomething();
   void DoSomethingElse();
    }
    public class MyBaseClass
    {
     public void DoSomething()
{  }
    }
    public class MyDerivedClass:MyBaseClass,IMyInterface
    {
public void DoSomething()
{}  
    }
------------------------------------------
    基类实现的接口,意味着派生类隐式的支持这个接口,如下:
    public interface IMyInterface
    {
       void DoSomething();
   void DoSomethingElse();
    }
   
    public MyBaseClass:IMyInterface
    {
        public virtual void DoSomething()  {}
    }

    public class MyDerivedClass:MyBaseClass
    {
        public override void DoSomething() {}  //隐式支持基类继承的接口
    }
   
    如果派生类是隐藏 而不是 重写 接口, 则方法IMyInterface.DoSomething()总是引用基类版本,即使派生类用接口访问也是调用基类方法。
         ---------------------------------------------------------
    显示 及 隐式 执行 接口成员
public class MyClass: IMyInterface
{
   void IMyInterface.DoSomething() {} // 显示执行
   public void DoSomethingElse() {} // 隐式执行
}
       
        显示执行:
MyClass myObj = new MyClass();
IMyInterface myInt = myObj;
myInt.DoSomething();
        隐式执行:
        MyClass myObj = new MyClass();
myObj.DoSomethingElse();
只有隐式执行的DoSomethingElse()才可以用MyClass的对象实例直接访问
-------------------------------------------------------
    如果接口中有属性(有get和set访问器),在实现接口的类中,可以添加访问器,但添加的访问器的修饰符(如,public,protected...),必须比接口中定义的更加严格才可以添加。
    public interface IMyInterface
    {
  int MyIntProperty
{
   get;
}
    }

    public class MyBaseClass: IMyInterface
    {
protected int myInt;
public int MyInterProperty
{
   get
{
   return myInt;
}
   protected set // 相比接口中多了set访问器,但访问修饰符为protected,比get的更加严格
{
   myInt = value;
}
}
    }

20. partial 关键字
部分类定义:
public partial class MyClass: IMyInterface1
{
.....
}
public partial class MyClass: IMyInterface2
{
.....
}
        以上两个和在一起等价于:

     public class MyClass:IMyInterface1, IMyInterface2
{
......
}
-----------------------------------
部分方法定义:
部分方法可以是static的,但总是private的,且 不能有返回值。使用的参数不能是out参数,可以是ref参数。不能使用virtual,abstract,override,new,sealed 和 extern。
执行编译时,如果代码包含一个没有执行代码的“部分方法”,会完全删除该方法,并且会删除对该方法的全部引用。
public partial class MyClass
{
partial void MyPartialMethod();   //有partial关键字
}
public partial class MyClass
{
partial void MyPartialMethod()  //有partial关键字
{
// method implementation
}
}

21. System.Collections名称空间中的几个接口
· IEnumerable 可以迭代集合中的项,该接口的唯一的方法为 GetEnumerable()可以迭代集合中的各项。实现该接口的类才能用foreach进行迭代。MSDN:http://msdn.microsoft.com/zh-cn/library/system.collections.ienumerable(VS.80).aspx
· ICollection (继承于IEnumerable)可以获取集合中项的个数,并能把项复制到一个简单的数组类型中
· IList(继承于IEnumerable 和 ICollection)提供了几个的项列表,并可以访问这些项,以及其他一些与项列表相关的功能
· IDictionary(继承于IEnumerable 和 ICollection)类似于IList,但提供了可以通过“键码值”而不是“索引”访问的项列表
System.Array类实现了IList、ICollection和 IEnumerable,但不支持IList的一些更高级的功能。它表示大小固定的项列表
System.ArrayList类实现了IList、ICollection和 IEnumerable,可以表示大小可变的项列表。
   Arraylist集合可以用AddRange()添加好几个项。这个方法接受带有ICollection接口的任何对象。但该方法不是任何借口的一部分,是ArrayList专有的。
   IList的IndexOf()返回找到对象的索引;如果某对象在列表中出现多次,则 IndexOf 方法将始终返回找到的第一个实例。
  
22. 定义集合-应用System.Collections.CollectionBase抽象类
CollectionBase类有接口 IEnumerable, ICollection 和 IList,但只提供了一些要求的代码。
CollectionBase提供了两个受保护的属性 List 和 InnerList,List可以通过IList接口访问项,InnerList则是用于存储项的ArrayList对象。
例1.
public class Animals : CollectionBase
{
   public void Add(Animal newAnimal)
   {
List.Add(newAnimal); // 利用List属性操作集合中的项
            }
   public void Remove(Animal oldAnimal)
   {
List.Remove(oldAnimal);    // 利用List属性操作集合中的项
   }
   public Animals()
   {}
}
结论:IList的Add() 和 Remove()方法为强类型话的方法。在本例中只能处理Animal类 或 派生于Animal的类。而前面介绍的ArrayList执行代码可以处理任何对象。
例2.
Animals animalCollection = new Animals();
animalCollection.Add(new Cow("Sarah"));
foreach(Animal in animalCollection)
{
   ........
}
结论:CollectionBase类可以对派生类的集合使用foreach语法
---------------------------------------------
CollectionBase的索引符

public class Animals: CollectionBase
{
   ....
 public Animal this[int animalIndex]
 {
       get
{
   return (Animal)List[animalIndex];   // 因为IList.List属性返回的是一个System.Object对象,所以需要进行显示类型转换
}
    set
{
   List[animalIndex] = value; // List使用索引符,在IList上,访问CollectionBase中的ArrayList.
}
 }
}
然后就可以使用:
animalCollection[0].Feed()
否则,只能用 ((Animal)animalCollection[0]).Feed();
------------------------------------------------------------
23. 定义关键字集合--应用System.Collections.DictionaryBase抽象基类
    DictionaryBase实现IEnumerable 和ICollection接口。 DictionaryBase简化了IDictionary接口的实现。
   
例1:
public class Animals: DictionaryBase
{
 public void Add(string newID, Animal newAnimal)
 {
Dictionary.Add(newID, newAnimal);  //利用Dictionary访问集合项
 }
 
 public void Remove(string animalID)
 {
  Dictionary.Remove(newID);
 }
 public Animals() {}
 public Animal this[string animalID]
 {
  get
{
 return (Animal)Dictionary(animalID);
}
set
{
 Dictionary[animalID] = value;
}
 }
}
--------------------
foreach工作方式
DictionaryBase需要用 System.Collections.DictionaryEntry结构. 要得到DictionaryBase派生类对象本身(比如,Animal对象本身),就必须使用这个结构的Value成员,也可以使用Key成员得到相关的关键字。
foreach (DictionaryEntry myEntry in animalCollection)    //animalCollection是 Dictionary派生类的对象
{
  Console.WriteLine("{0} AND {1}", myEntry.Value.ToString(),((Animal)myEntry.Value).Name);   //也可以用迭代器实现如下的代码,具体见下一条目。
}
想等价的代码:
  foreach (Animal myAnimal in animalCollection) // animalCollection是CollectionBase派生类的对象
{
  Console.WriteLine("{0} AND {1}", myAnimal.ToString(),myAnimal.Name());
}

24. 迭代器
·如果要迭代一个类,可使用GetEnumerator(),其返回类型是IEnumerable。
·如果要迭代一个类成员,例如一个方法,则使用IEnumerable。

迭代类成员(方法):
public static IEnumerable SimpleList()
{
  yield return "string 1";
  yield return "string 2";
  yield return "string 3";
}

public static void Main(string[] args)
{
   foreach (string item in SimpleList())
Console.WriteLine(item);
   Console.ReadyKey();
}

运行结果为:
string 1
string 2
string 3

可以用" yield break; " 中断信息返回
----------------------------
迭代类:
public class Primes
{
   private long min;
   private long max;
  
   public Primes() : this(2,100) {...}
   public Primes(long minimum, long maximum) {...}
  
   public IEnumerator GetEnumerator()
{  ....
  if(...)
  yield return possiblePrime;
}
}

static void Main(string[] args)
{
   Primes primesFrom2To1000 = new Primes(2,1000);
   foreach (long i in primesFrom2To1000)    // 因为类Primes实现了GetEnumerator方法,所以可以迭代。
{ Console.Write("{0}",i); }
   Console.ReadyKey();
}
-------------------------------------------------
迭代器和DictionaryBase集合
public class Animals: DictionaryBase
{
 public void Add(string newID, Animal newAnimal) {Dictionary.Add(newID, newAnimal);}
 public void Remove(string animalID) {Dictionary.Remove(animalID);}
 public Animals() {...}
          public Animal this[string animalID]
 {
    get
{
 return (Animal)Dictionary[animalID];
}
    set
{
 Dictionary[animalID] = value;
}
 }

 // 添加迭代器
 public new IEnumerator GetEnumerator()
 {
    foreach (object animal in Dictonary.Values)
yield return (Animal)animal;
 }
}
        接下来就可以在迭代集合中使用Animal对象了
foreach(Animal myAnimal in animalCollection)
  Console.WriteLine("{0} AND {1}", myAnimal.ToString(),myAnimal.Name);
25. 浅度复制 与 深度复制
    ·i 浅度复制
利用受保护(protected)的方法 System.Object.MemberwiseClone(),无参数,返回对象类型。
例:
public class Cloner
{
   public int Val;
   public Cloner(int newVal) { Val = newVal;} // 构造函数
  
   public object GetCopy()
   {
return MemberwiseClone();// MemberwiseClone() 对当前对象执行浅度复制。
   }
}
局限:当类中有引用类型时,浅度复制得到的对象,所以用的部分与源对象相同。
   
    ·ii 深度复制
类要求实现接口 ICloneable,该接口有一个Clone()方法,无参数,返回对象类型。
public class Content
{
   public int Val;
}
public class Cloner: ICloneable
{
   public Content MyContent = new Content();
   public Cloner(int newval) { MyContent.Val = newVal; }
  
   public object Clone() //实现Clone方法,实现深度复制
   {
Cloner clonedCloner = new Cloner(MyContent.Val);
       return clonerCloner;
   }
         }

注意:深度复制的代码( Clone() )是要自己编写的。
      Clone()是一个递归过程:
               上例中Content类中没有引用类型,所以,可只对Cloner()深度复制。
      如果,Content中有引用类型就需要如下代码:
public object Clone()
{
   Cloner clonedCloner = new Cloner();
   clonedCloner.MyContent = MyContent.Clone();
   return clonedCloner;
}

26. 封箱 & 拆箱
    封箱(boxing),  值类型 -» System.Object 类型 || 转换为值类型实现的接口类型
    拆箱(unboxing),相反过程。
 
    struct MyStruct
    { public int Val;   }

    MyStruct valType1 = new MyStruct();
    object refType = valType1;    // 封箱
......
    MyStruct valType2 = (MyStruct)refType; // 拆箱
----------------
    Struct Mystruct: IMyInterface
    {......}

    Mystruct valType2 = new MyStruct();
    IMyInterface refType = valType2;     // 封箱到接口对象中
    由以上,可知,封箱是隐式的(不需要显示转换),而拆箱是显示的(需要显示转换)

27. is 运算符
    «operand» is «type»
    ·如果 «type» 是一个类, «operand» 也是该类型,或继承了该类,或封封箱到该类型, 结果为TRUE。
    ·如果 «type» 是一个接口,«operand» 也是该类型,或实现了该接口,结果为TRUE。
    ·如果 «type» 是一个值类型,«operand»也是该类型,或被拆箱到该类型中,结果为TRUE。

28. 运算符重载
    public class ClassA
    {
public int Val;
 
public static ClassA operator +(ClassA op1, ClassA op2)  运算符重载声明格式,如果是一元运算符,那就只有一个参数。
{
   ClassA returnVal = new ClassA();
   returnVal.Val = op1.Val + op2.Val;
   return returnVal;
}
    }

    ClassA  op1,op2,op3;  ......
    op3 = op1 + op2;    
    ----------------------------------
    混合类型操作符:
    ......
    public static ClassC operator +(ClassA op1, ClassB op2 )
    {
ClassC returnVal = new ClassC();
returnVal.Val = op1.Val + op2.Val;
return returnVal;
    }
    ......
    混合类型操作符重载注意:
    不要把 签名相同的运算符 添加到 多个类中。因为程序不知道该调用哪个运算符。
     比如:如果ClassB也定义了上面的操作符,代码就会失败。
    另外,操作数的顺序 和 运算符重载的 顺序 要 相同。
    ClassA op1 = new ClassA();
    ClassB op2 = new ClassB();
    ClassC op3 = op2 + op1;  // 该代码会出错,因为重载运算符中定义的是 (ClassA op1, ClassB op2), 先ClassA 后 ClassB的顺序。
    ----------------------------------
    可以重载的运算符:
    ·一元: +, -, !, ++, --, true, false
    ·二元: +, -, *, /, %, &, |, ^, ««, »»
    ·比较: ==, !=, «, », «=, »=

    "+=" 不能重载,但重载 "+" 相当于重载 "+="
    "«" 和 "»"  以及 "«=" 和 "»=" 需要成对重载
    重载true 和 false后,就可以在布尔表达式中使用类,如 if(op1) {....}。
    重载"==" 和 "!="时,最好也重写Object.Equals() 和 Object.GetHashCode()。
   public override bool Equals(Object op1) {......}  //注意,参数是Object类型
public override int GetHashCode() {......}

29. IComparable 和 IComparer 接口
    可以使用这两个接口对 集合排序。
      ·IComparable 在要比较的对象的类中实现,提供了CompareTo(..)方法,可比较该对象,和另一个对象。
      ·ICompare 在一个单独的类中实现,提供了Compare()方法,可比较任意两个对象。
     一般,用IComparable给出类的默认比较代码,用实现ICompare的其他类给出非默认比较代码。
   
   类Compare在System.Collections名称空间中,提供了ICompare接口的默认实现方式。可以使用Compare.Default静态成员,接着使用Compare()方法。比如,Compare.Default.Compare(«T» x, «T» y)。
     Compare类的注意事项:
·检查传给Compare()的对象是否支持 IComparable。如果支持,就是用对象类的代码。
·null 小于 其他对象。
·字符串根据当前“特定区域性的信息”(非托管代码称为“区域设置”)处理。要使用不同的“区域信息”,Compare类必须实例化,以便传送System.Globalization.CultureInfo对象。
·字符串处理时区分大小写。要不区分大小写,需要用CaseInsensitiveComparer类。
   
    System.Collections名称空间中的一些类没有排序方法,比如,CollectionBase类。  而ArrayList的Sort()方法,只有在ArrayList中填充简单类型时,才能进行排序。对于自己定义的类,必须在类中实现IComparable或是创建一个类实现ICompare类,来进行比较。
     下面,分别用 IComparable 和 ICompare来实现自定义类型的排序:

class Person: IComparable
{
   public string Name;
   public int Age;
     public Person(string name, int age) {.....}
     
   public CompareTo(Object obj)    // 当Person的ArrayList进行Sort()排序时,会调用该函数实现排序功能。
   {
if(obj is Person)
{
  Person otherPerson = obj as Person;
  return this.Age - otherPerson.Age;
}
else
{
  throw new ArgumentException( "......" )
}
      }
}    
       -----------
public class PersonCompareName: ICompare
{
  public static ICompare Default = new PersonCompareName();
  public int Compare(Object x, Object y)
  {
      if(x is Person && y is Person)
{
   return Compare.Default.Compare(
((Person)x).Name, ((Person)y).Name );
               else
  throw new ArgumentException(".......");
}
  }
}
-----------

static void Main()
{
   ArrayList list = new ArrayList();
            list.Add(new Person("Jim",30));
.....
            list.Add(new Person("Bob",22));
            list.Sort();   // 因Person类实现了IComparable接口,所以,Sort()调用CompareTo(Object obj)方法进行排序。
            list.Sort(PersonCompareName.Default); // 调用其他实现ICompare的类(PersonCompareName),调用Compare()方法进行排序。
}

30. 转换
    · 重载转换运算符
在不相关的类型之间转换时,需要定义 显示 或 隐式 转换:
public class ConvClass1
{
  public int val;
 
  public static implicit operator ConvClass2(ConvClass1)  // 定义 ConvClass1到ConvClass2的隐士转换
  {
ConvClass2 returnVal = new ConvClass2();
returnVal.val = op1.val;
                return returnVal;
  }
}

public class ConvClass2
{
  public double val;
           public static explicit operator ConvClass1(ConvClass2 op1)
  {
ConvClass1 returnVal = new ConvClass1();
  checked (returnVal.val) = (int)op1.val;
return returnVal;
           }
}

ConvClass1 op1 = new ConvClass1();
ConvClass2 op2 = new ConvClass2();
.....
op2 = op1;  //根据定义,可以隐士转换
op1 = (ConvClass1)op2;  //根据定义,需要显示转换
  ---------------------------------------
    · as 转换为指定的引用类型
       «operand» as «type»
·«operand» 的类型是«type»类型
·«operand» 可以隐式转换为«type»类型
·«operand» 可以封箱到«type»类型中
如果不能转换,则表达式返回 null。返回null而不是异常,比较好处理。

31. 可空类型 System.Nullable«T»
    ·声明可空的值类型。
      System.Nullable«int» nullableInt;
      nullableInt = null;  //因为int类型为值类型,如果nullableInt不是可空类型,那么它不能用null赋值。
      .......
      if (nullableInt == null) {......}//可以像测试引用类型一样,测试可空类型,看它是否为null
 
      另外,还可以使用HasValue属性:
      if( nullableInt.HasValue ) {.......} //引用类型不能用HasValue属性,会抛出异常。因为,引用类型的null,表示没有对象,当然就不能通过对象访问。
      ------------------
      另一种,声明可空类型的语法:
      int? nullableInt;  // int?是System.Nullable«int» 的缩写。 
   
    ·运算符 和 可空类型
      int? op1 = 5;
      int? result = op1*2;   // 可以运算
      ******
      int result = op1*2;   // 不能编译
      ******
      int result = (int) op1*2; //可以编译并运算,但当op1为null时,会抛出System.InvalidOperationException异常。
     
      当可空类型进行运算时,如果有操作数为null, 除bool?之外的简单可控类型,运算结果是null。解释为不能运算。
      对于bool?, 如果不需要值为null的操作数就能算出结果,那么就可以运算;如果需要,结果就为null。比如:true|null 结果为true(只要有true,结果就为ture), false|null结果为null(第一个操作数为false,所以需要另一个值来运算,所以结果为null)。
      ----------------------
     ·??运算符
       op1??op2;
       等效于:
       op1==null ? op2:op1;

32. 泛型 System.Collections.Generic
    这个名称空间中包含处理集合的泛型类型。
    ·List«T»
      成员: Count, Add(T item), AddRange(IEnumerable«t»), AsReadOnly(), Capacity, Clear(), Contains(T item), CopyTo(T[] array, int index), GetEnumerator(), IndexOf(T item), Insert(int index, T item), Remove(T item), RemoveAt(int index), Item....
      例:
Animals animalCollection = new Animals();   //Animals继承了CollectionBase。
     可替换为:
List«Animal» animalCollection = new List«Animal»();
  另一种修改方法为:  
  public class Animals : List«Animal» {.......}  //该方法,可以在集合类Animals中添加额外的成员。

CollectionBase类的用途:1. 向后兼容。2.更多的控制向类的“用户”展示的成员。比如,将集合的Add()方法,使用内部访问修饰符。
      -------------------------
     ·对泛型列表 的 排序 和 搜索
       对List«T»排序的两个方法:
       1. 在需要的类上提供IComparable«T» 或  提供 ICompare«T»接口
       2. 提供泛型委托作为排序方法
 排序 和 搜索 的泛型委托:
 ·Comparison«T» : 这个委托类型用于排序方法,器返回类型 和 参数 是 int method (T objectA, T objectB).
 ·Predicate«T» : 这个委托类型用于搜索方法,其返回类型 和 参数是 bool method(T targetObject).
       例:
 public class Vectors : List«Vector»
 {
    public Vectors() {....}
    public Vectors(IEnumerable«Vectors» initialItems)
    {
foreach (Vector vector in initialItem)
{
   Add(vector);
}
             }
    ......
 }
        添加一个新类VectorDelegates,用于提供泛型委托所用的方法
 public static class VctorDelegates
 {
    public static int Compare(Vector x, Vector y)  //排序方法
    {
if(x.R » y.R)
{
  return 1;
}
else if(x.R « y.R )
    {
return -1;
            }
return 0;
  
    }
    public static bool TopRightQuadrant(Vector target)  //用于搜索
    {
if(target.Theta =» 0.0 && target.Theta«= 90.0)
{
  return true;
}
else
{
  return false;
}
             }
 }
 
 在主程序中 应用 排序 和 搜索 方法:
 static void Main(string[] args)
 {
    Vectors route = new Vectors();
             route.Add(new Vector(2.0, 90.0));
.....
    Comparison«Vector» sorter = new Comparison«Vector»(VectorDelegates.Compare); //绑定委托
             route.Sort(sorter); //完成排序
.....
    Predicate«Vector» searcher = new Predicate«Vector»(VectorDelegates.TopRightQuadrant); //绑定委托
    Vectors topRightQuadrantRoute = new Vectors(route.FindAll(searcher)); // 完成搜索
  .....    
 }
 
33. Dictionary«K,V»
    ·可以使用Keys 和 Values 属性迭代集合中的 键和值。
Dictionary«string ,int» thing = new Dictionary«string, int»();
        foreach (string key in thing.Keys)  //用Keys属性迭代
{......}

foreach (string value in thing.Values) //用Values属性迭代
{......}
        ---------------
     可以迭代集合中的项,用KeyValuePair«K,V»实例来获取(与DictionaryEntry对象相同)
foreach(KeyValuePair«string, int» thing in things)
{.......}
   
   ·使用不区分大小写的方法来比较字符串
Dictionary«string, int» things = new Dictionary«string, int»(StringCompare.CurrentCultureIgonreCase);
此时,如果执行下面的操作,会抛出ArgumentException异常
things.Add("GREEN", 29);
things.Add("green",94);  //因为不区分大小写,以上两个实例拥有相同的键值,所以会异常。

34.泛型
    定义泛型类

         无绑定类型:

            class MyGenericClass«T» {.......}

            class MyGenericClass«T1,T2,T3» {.......}

            class MyGenericClass«T1,T2,T3»

                {
                    private T1 innerT1Object;

                    public MyGenericClass(T1 item)  {innerT1Object = item;}

                    // innerT1Object = new T1();     //这行代码不能编译通过,因为不能假定T1是什么类型。
                                                                //不知道T1是什么也就不能使用它的构造函数(因为T1可能没有可公共访问的构造函数)。

                    .....

                }

           default关键字:
            public MyGenericClass()
            { innerT1Object = default(T1);  }    //不能赋给innerT1Object的值为null,因它可能是值类型。
                                                            //所以用default,会赋给innerT1Object合适的默认值,比如,引用型赋值为null,整型赋值为0等等。
      

        约束类型:

            ? 疑问-»P282中,为什么MyGenericClass«Cow» = new  MyGenericClass«Cow»是可以编译的?

            where关键字:
            class MyGenericClass«T» where T: constraint1, constraint2   {...........}

            // 其中constraint1 & constraint2为约束条件。 可以n个约束条件,用逗号分开。


           class MyGenericClass«T1, T2» where T1: constraint1 where T2: constraint2

            // 也可以用多个where约束


           class MygenericClass«T1,T2» : MyBaseClass, IMyInterface where T1: constaint1 where T2: constaint2 {........}

           // 约束要在继承说明符后面

           
           class MyGenericClass«T1,T2» where T2:T1 {...}  //这称为“裸类型约束”,一个泛型 做 另一个泛型的约束。 但不能循环,如:...where T2: T1 where T1:T2

           一些可用的约束:struct, class, base-class, interface, new() 见书P283 表 12-5 。如果new()作约束,它必须是最后一个约束。


        例:
            public abstract class Animal  {......}  

            public class Chicken : Animal {......}

            public class Cow: Animal {....}

            public class SuperCow : Cow {......}


            public class Farm«T» : IEnumerable«T» where T :Animal

            {
                private List«T» animals = new List«T» ();

                public List«T» Animals { set { return animals;} }

               

                public IEnumerator«T» GetEnumerator() {return animals.GetEnumerator();}      //实现了IEnumerable«T»接口,这样,Farm«T»可以直接迭代(如:foreach(Cow cow in    
                                                                                                                          //Farm«Cow»)),不需要用Farm«T».Animals(如:foreach (Animal animal in Farm«T».Animals ))。

                IEnumerator IEnumerable.GetEnumerator() {return animals.GetEnumerator();}   //另一方面,因为IEnumerable«T»继承自IEnumerable,所以还需要实现IEnumerable

                .......

            }

       

           

         从泛型类中继承:

             class SuperFarm«T» : Farm«T» where T:SuperCow {.....}  //Farm«T»中T被约束为Animal,而SuperCow为Animals的子集,所以可以约束。
                                                                                            //如果SuperCow换成 struct(因为T 不能转换为Farm«T»中的T) 或 class(是 T 的超集)就不能编译。

                                                                                            //结论: SuperFarm«T»继承 Farm«T»,所以,SuperFarm«T» 至少要受到 Farm«T»所受到的约束。

            

             public class Cards: List«Card» ,ICloneable {...} // 继承一个泛型类,必须提供所有必须信息。
                                                                             // 如果,List«Card»换成 List«T»那么编译会失败。

        泛型运算符:

            隐式转换运算符:

                public static implicit operator List«Animal» (Farm«T» farm)

                    {
                        List«Animal» result = new List«Animal»();

                        foreach (T animal in farm)

                        {
                            result.Add(animal);

                        }

                        return result;

                    }   

            重载运算符:

                public static Farm«T» operator + (Farm«T» farm1, List«T» farm2)

                {
                    Farm«T» result = new Farm«T»();

                    foreach (T animal in farm1)
                    {
                        result.Animals.Add(animal);

                    }

                    foreach ( T animal in farm2)

                    {
                        if (!result.Animals.Contains(animal)) { result.Animals.Add();}                      
                    }                   
                    return result;

                }
                public static Farm«T» operator +(List«T» farm1 , Farm«T» farm2) {return farm2 + farm1;}  // 注意 “重载+” 时的参数, 第一个是 Farm«T»+ List«T», 第二个是List«T»+ Farm«T»
            --------------------------------

            另一种方法:

                public static Farm«T» operator +(Farm«T» farm1, Farm«T» farm2) {..............}

                public static implicit operator Farm«Animal» (Farm«T» farm) {........}      

                //隐式转换,将对象转换为Farm«Animal»类型,然后,可以利用重载的 “+” 进行运算。

       
    定义泛型方法:

        非泛型类的 泛型方法:

            public class Defaulter

            {
                public T GetDefault«T» () {.....}

            }

         泛型类的 泛型方法:

            public class Defaulter«T»

            {
                public T GetDefault«T1»(){........}     //  T1 和 T 不能相同,否则编译失败。

            }

        泛型方法的重载:

        public void ProcessT«T» (T op1) {.......}

        public void ProcessT«T, U» (T op1, U op2) {.......}

        使用哪个方法,取决于 参数 的个数。


35. ::运算符 & 全局名称空间限定
       :: 用于别名访问

        using MyAlias = MyRootSpace.Myspace;      // 设定 别名 MyAlias

        namespace MyRootNamespace

        {
            namespace MyAlias                             // 写一个与 别名 相同的 命名空间

            {
                public class MyClass {.........}     

            }


            namespace Myspace                          // 这个是设定到 “别名” -MyAlias 的 命名空间

            {
                public class MyClass {.........}

            }

        }

        ************

        //应用方式

        MyAlias.MyClass  引用的是   MyAlias命名空间的 类

        MyAlias::MyClass  引用的是   Myspace 命名空间的 类

            ---------------------------------------------------------------------

        :: 还经常 和 global 关键字 一起使用

         global是 “顶级根名称空间” 的 别名
         global::System.Collections.Generic.List«int»

         在大项目中才会出现,防止名称空间重名造成的引用混乱。


36. 定制异常
    异常的基类:System.Exception 和 System.ApplicationException

        System.SystemExceptiron用于.NET Framework预定义的异常的基类。

        System.ApplicationException由开发人员用于派生自己的异常类。

        这两个基类派生于Exception,但都没有扩展Exception类的功能。可以继承Exceptiron进行定制,但最好通过分类,继承上面两个基类。有助于分清是那种异常。
       

        例:

        public class CardOutOfRangeExceptiron:Exception    //定制异常类
        {
            private Cards deckContents;

            public Cards DeckContents{ get {return deckContents;}}

            public CardOutOfRangeExceptrion(Cards sourceDeckContents) : base("There are only 52 cards in the deck.")  {deckContents = sourceDeckContents;}

        }

       
        //******* 在方法中使用定制异常**********

        public Card GetCard(int cardNum)

        {
            if (cardNum »= 0 && cardNum «= 51 )

                return cards[cardNum];

            else
                throw new CardOutOfRangeException(cards.Clone() as Cards);

        }


        //********测试************

        Deck deckTest = new Deck();

        try{ Card myCard = deckTest.GetCard(60);}  //GetCard(60)中60超出范围,引发异常

        catch (CardOutOfRangeException e) 
        {
            Console.WriteLine(e.Message);                 // 抛出在定制异常时,用基类初始化的提示(e.Message)          

            Console.WriteLine(e.DeckContents[0]);      // 通过定制异常,获取对象(e.DeckContents[0])。

        }

        //*******输出结果:**********    
        There are only 52 cards in the deck.  

        The ace of clubs                              

36. 事件
    自定义事件:

        public delegate void MessageHandler(string messageText);      // 第一步: 定义委托类型
        ......
        public class Connection
        {
            public event MessageHandler MessageArrived;        // 第二步: 声明事件。 用event关键字 和 要使用的委托类型 MessageHandler。

            .......

            private void CheckForMessage(object source, MessageEventArgs e)

            {
                ....

                if(MessageArrived != null)                // 判断MessageArrived是否有引用事件处理程序。用+=订阅事件(把事件与处理程序关联起来) 。

                {  MessageArrived("Hello Mum!"); }                 // 第三步: 引发事件。 (此例中,是在 另一个事件处理程序中进行引用)
            }            
        }

    *********订阅事件**********

        public class Display

        {
            public void DisplayMessage(string message) { Console.WriteLine("Message arrived: {0}", message );}        //定义事件处理程序

        }


         static void Main(string[] args)

        {
            ........   

            Connection myCon = new Connection();

            Display myDisplay = new Display();

            mycon.MessageArrived += new MessageHandler(myDisplay.DisplayMessage);      // 用+=订阅事件。 MessageArrived为前面声明的事件;
                                                                                                                       //MessageHandler为前面定义的委托类型;

                                                                                                                       //DisplayMessage为定义的事件处理程序,与 委托MessageHandler的签名相同。

            ........    
        }

        ---------------------------------------------------------------------------------

    事件的参数:

        前面 例子中的 委托 包含了事件处理程序中常见的两个参数: object source & MessageEventArgs e。

            这两个参数可以在定义委托时自己定义,比如: public delegate void MessageHandler(Connection source, MessageArrivedEventArgs e);   //Connection为前面定义的类

       

        自定义事件参数:

            public class MessageArrivedEventArgs : EventArgs               // System.EventArgs

            {
                private string message;

                public string Message {get { return message;}}

                public MessageArrivedEventArgs() {.......}
                ..........

            }

        利用派生于 System.EventArgs类的参数,可以提供更多的必要信息。另外,还可以实现参数的多态性。如下:
            Console.WriteLine( ( (MessageArrivedArgs)e ).Message );

       ---------------------------------------------------------------------------------
    返回值 和 事件处理程序:

        推使用 void 类型的事件处理程序,且避免使用out类型参数。

        但如果事件处理程序有返回类型,那么当调用好几个事件处理程序时,返回最后一个订阅的事件处理程序返回的值。
          --------------------------------------------------------------------------------

    匿名方法:

        匿名方法不是某个类上的 方法,而纯粹是为用作委托目的而创建的。

        创建匿名方法的代码:

        delegate(parameters)

        {          
            // 匿名方法代码

        };   //注意这里有个分号!!


        例:

            myConnection.MessageArrived += deleage(Connection source, MessageArrivedEventArgs e) { Console.WriteLine(source.Name);......};


=================================================================================================================================
C# 3.0部分

38.自动属性 和 部分方法
   自动属性: public string Name{get;set;}


39.初始化器
    初始化器会首先调用默认初始化函数,如没有,有时候编译器会自动提供一个。有时则必须提供一个。

    对象初始化器:

        例:

            public class Curry    // 定义一个类

            {
                public string MainIngredient {get; set;}

                public string Style {get; set;}

                public int Spiciness{get; set;}

                ......

            }

            *************************

            Curry testCurry = new Curry

            {
                MainIngredient = "panir tikka",         // 初始化时,各个参数用","分隔

                Style = "jalfrezi",

                Spiciess = 8

            };       //注意有分号,可以把代码写在一行


        ********************************

         如果,类型比较复杂,初始化器可以进行嵌套:

            Curry testCurry = new Curry

            {
                MainIngredient = "panir tikka",

                ......

                Orign = new Restaurant { name = "King's Balti", Location = "York Road",.....};

            };


    集合初始化器(常常会与LINQ技术一起使用):

        例:

            List«Curry» moreCurries = new List«Curry»

            {
                new Curry { MainIngredient = "Chicken", Style = "Pathia", Spiciness = 6 },

                new Curry { MainIngredient = "Vegetable", Style = "Korma", Spicines = 3 },

                new Curry { MainIngredient = "Prawn", Style = "Vindaloo", Spiciness = 9}

            };

            可以代替:
            List«Curry» curries = new List«Curry»();

            curries.Add(new Curry("Chicken","Pathia",6));           

            ......

            curries.Add(new Curry("Prawn","Vindaloo",9));

      ***************************
            public class Animal {.............}

            public class Cow:Animal {......}

            public class Chicken:Animal {.......}

            public class SuperCow:Animal {......}

           

            static void Main(string[] Args)    
            {
                Farm«Animal» farm = new Farm«Animal»

                {
                    new Cow {Name = "Norris"},   

                    new Chicken {Name = "Rita"},

                    new Chicken();

                    new SuperCow{ Name = "Chesney"}

                };

                 ................

            }

            要是上面的初始化器能够有效需要做以下两件事:

            ·i 给派生于Animal的类添加默认构造函数。Name属性可以利用基类的默认构造函数初始化。 public Animal(){name = “the animal is no name” ;}

            ·ii 为Farm«T» 添加Add方法:

                public Farm«T» : IEnumerable«T» where T: Animal

                {
                     public void Add(T animal)  {  animal.Add(animal);}    // 添加Add方法
                }

                因为编译器在集合初始化器中要为提供的每一项调用Add()方法。在上面的初始化器中编译器猜不出是要用Animal.Add()填充属性,所以要在Farm«T»中添加Add方法。

                也可以用下面的方法初始化:

                Farm«Animal» farm = new Farm«Animal»

                {
                    Animal =                                                     // 这样就不需要为Farm类添加Add()方法了

                    {
                        new Cow {Name = "Norris"},    
                        new Chicken {Name = "Rita"},

                        new Chicken();

                        new SuperCow{ Name = "Chesney"}
                    }
                };

           

40. 推断类型 var
    var并不是声明了一个没有类型的变量(C#是强类型化的语言)。
    在用var生命变量时,必须同时初始化该变量,以便让编译器确定变量类型。如果编译器不能确定,就不能编译。

    比如:

            var myVar = 5; // 此时,myVar被确定为int型。

            var myArray = new[] {4,5,2};

            在隐式指定数组类型时,初始化器中使用的数组元素必须是:

            ·相同的类型

            ·相同的引用类型 或 空

            ·所以元素的类型都可以隐式的转换为一个类型

   

    总之,如果如能确定var变量的类型,编译就无法通过。


41. 匿名类型
    常常有一些类只是提供属性。对底层数据模式的任何修改都要添加,删除或修改定义类的代码。
    匿名类可以简化这个编程模式的一种方式。

    例:

    var curries = new[]

    {
        new { MainIngredient="Lamb", Style="Dhansak", Spiciness = 5},

        new { MainIngredient="Lamb", Style="Dhansak", Spiciness = 5},

        new { MainIngredient="chicken", Style="Dhansak", Spiciness = 5},

    };

   

    在IDE中查看var test = new {MainIngredient="Lamb", Style="Dhansak", Spiciness = 5};中test的类型是'a, '符号在IntelliSense中表示匿名类型。

    匿名类型是只读的,不能修改。

    在上面实例化的过程中,编译器会对比所创建的实例,会创建一个类型的三个实例,而不是三个类型。但不会在程序中查找相对应的类型进行匹配。


42. 扩展方法
    扩展方法,可以扩展类型的功能,但无需修改类型本身。甚至可以扩展不能修改的类型,包括.net framework中定义的类型。

    语法:

        public static class ExtensionClass        //类需要时静态类
        {
            public static ReturnType ExtensionMethodName (this TypeToExtend instance)  //方法也要是静态的,this关键字必须有,TypeToExtend是要扩展的类。此处可以有多个参数。

            {
                .....

            }

        }


        调用方式: TypeToExtend myVar;      myVar.ExtensionMethodName(); 或 ExtensioClass.ExtensionMethodName(myVar);

       

    例:

        public static class ExtensionLibExtensions

        {
            public static string ToTitleCase(this string input string, bool forceLower)

            {
                inputString = inputString.Trim();

                if(...)......

            }

        }

       

        在程序中调用:   

        ...

        using ExtensionLib;  //类ExtensionLibExtensions所在的命名空间

        ...

        static void Main(string[] args)

        {
            ...

            string sourceString = Console.ReadLine();

            sourceString.ToTitleCase(true);  //true为方法声明中的第二个参数 bool foreceLower.

        }


43. λ表达式
    λ表达式用于简化C#编程的某些方面,尤其是与LINQ合并的方面。

    
    把λ表达式用于匿名方法:

        例:

             
            myTimer.Elapsed += (source, e) =» Console.WriteLine("Event handler called after {0} milliseconds.", (source as Timer).Interval );  //应用λ表达式。
                                                                                                                                                                                  //(source, e)参数应用了匿名类型,会根据上下文推到类型。
                                                                                                                                                                                  // =»把参数列表 和 表达式体分开。
                                                        
            可以代替内联的匿名方法:

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

            这两段代码会被编译为相同 或 相似 的 MSIL代码。
   

    λ表达式的参数:
        上面的(source,e)采用了匿名类型。实际上也可以定义类型如: (int paramA , int paramB)=» paramA+ paramB

        但不可以(int paramA, paramB)=»....., 只能要么全部指定类型,要么全部采用匿名类型。 不能混用。


        如果,只有一个参数可以省略(),如: param1 =» param1*param1

   

        还可以,定义 无参数 的λ表达式,使用空括号来表示:() =» Math.PI  
        

    λ表达式的语句体:

         多行表达式时如下:

        (param1, param2)=»

         {
            // 多行表达式

            return returnvalue; //如果有返回类型,可以使用return语句。

         }

         例:

            PerformOperations((int paramA, int paramB)=»param1+param2);

            可以改写为:

            performOperations(delegate(int paramA, int paramB) {return paramA+ paramB;});

            还可改写为:

            performOperations((int paramA, int paramB) =» { return paramA+paramB;});


          单一表达式时,使用λ表达式比较简单。多个语句是,建议使用非匿名方法,这便于代码重用。

   

    λ表达式用做委托 和 表达式树:

        λ表达式有两种解释:

            ·i 解释为 委托 (如上面所描述的一样)

                一般可以把拥有至多4个参数 的表达式 表示为如下 泛型类型:

                    ·Action«»表示 不带 参数, 返回 void

                    ·Action«»表示 至多4个参数, 返回 void
                    ·Func«»表示 至多5个参数,返回非 void类型 。 返回类型放在参数列表最后。如:Func«int, int, int» 意思是,有两个int参数,返回类型是int。

          

           ·ii 解释为 表达式树(与LINQ关系密切)

                表达式树 是 λ表达式 的抽象表示,但不能直接执行。可以使用表达式树已编程方式分析λ表达式,执行操作,以响应λ表达式。

                     例:

                        LINQ架构包含一个泛型类Expression«»,用于封装λ表达式。使用这个类的一种方式是提取C#编写的λ表达式,把它转换为等价的SQL脚本,以便在数据库中直接执行。


     λ表达式 和 集合:
        学习Func«»泛型委托后,理解System.Linq空间中为数组提供的扩展方法。例Aggregate()定义的其中一个版本:

        public static TSource Aggregate «TSource»(this IEnumerable«TSource» source, Func«TSource, TSource, TSource» func );


        调用:

        int[] myIntArray = {2,6,3};

        int result = myIntArray.Aggregate((param1, param2)=»param1+param2);  //这个表达式会使 λ表达式调用两次(有三个数,先计算2+6,再计算8+3)。最后result=11。

 

你可能感兴趣的:(C#)