ü 数组:数组是一个对象继承自System.Array,数组一旦被创立大小就被固定,C#不支持动态数组。数组自带rank,length,getLength,sort等方法,矩形数组(某一维度的所有子数组都有相同长度)int[,] a=new int[3,6]->声明二维数组,初始化:a[i]=?;定义时初始化:int[,] a=newint[,]{{1,2},{2,3,5,6}}(隐式类型数组) int[,]a=new int[2,4]{{1,2,3,4},{2,3,5,6}}(显式类型数组)交错数组(子数组可以有不同数目的元素)声明:int[][] a=new int[3][]->有三个字数组,第二个空格不用填数;实例化:int[][] a=newint[3][];a[0]=new int[]{1,2,3};a[1]=new int[]{3,4,5}….先实例化顶层,再实例化底层,由于交错数组的子数组也是数组,因此交错数组也可以矩形数组(就是说,子数组可以是矩形数组->可以是多维的)
ü foreach方法:foreach(var i in arr1),foreach处理多维数组时,先从最左边的一个开始,处理完再处理第二个({{1,2},{3,4}},先处理{1,2}再处理{3,4})
ü 数组协变:将某个类型的对象赋值给数组-à如 class A;A[] array1=new a[3];a[0]=new A();a[1]=new A();…..
ü 数组继承的有用成员:Rank(获取数组的维度)->arr.Rank,Length(获取所有维度的元素总和)->arr.Length,GetLength(返回数组指定维度的长度)->arr.GetLength(0),Clear(设置某一范围内的元素值为0或者false或者null),Sort(在一维数组中对元素进行排序)->Array.Sort(arr),Clone(数组浅复制),IndexOf(返回一维数组中遇到的第一个元素的值),Reverse->Array.Reverse(arr)(一维数组中某一范围内的元素顺序反过来)
ü 再谈Clone:用法:int[]arr1=(int[])arr.Clone();克隆采用浅复制,就是说只会创造数组本身的克隆,如果是引用类型数组,它就不会复制引用本身的对象;克隆值类型的数组时会产生两个独立的数组,克隆引用数组的时候会产生指向相同对象的两个数组,引用类型变量的值是引用,而不是对象本身。
ü 委托:委托和类类似,但他保存的是一系列的方法;声明:delegatevoid MyDel(ref int x)->声明无返回值的带引用参数的委托,引入的参数会给所有的方法形参赋值
初始化:A a=new A();MyDelmy=new MyDel(a.play)->play方法的返回值和参数列表要和定义的时候一致
delegate void MyDel(ref int i); public class Tests { void main(String []args){ A haha = new A(); MyDel del = new MyDel(haha.play);//MyDeldel=haha.play; del += haha.let; del -= haha.play;
del(1);
del.Invoke(1);//调用委托 } } class A{ public void play(ref int a){ Console.Write(a++); } public void let(ref int b){ Console.Write(b++); } }
ü 匿名方法:MyDel del=delegate(ref int x){System.Console.Write(x++);};匿名方法可以访问它们外围作用域的局部变量和环境
ü Lambda表达式:针对匿名方法有更加简单的方式;MyDeldel=(int x)=>{return x++;};//MyDel del=x=>{return x++;};//MyDeldel=x=>{return x++;};//Mydel del=x=>x++;
ü 事件:1,事件提供了对它的私有控制委托的结构化访问;2,对于事件我们只可以进行添加,删除,调用等操作;3,事件被触发时依次调用调用列表中的方法;4,事件是成员,声明在类中执行,不能在一段可执行代码中声明
ü public delegate void EventHandler(object sender, EventArgs e); public class MyEventArgs:EventArgs{//重新定义EventArgs public String message; public MyEventArgs(String s){ message = s; } } public class Tests { void main(String []args){ MyTimer mc = new MyTimer(); A a = new A(); mc.Event += a.play; mc.Event += (object source, MyEventArgs arg) => { Console.Write("Lambda"); }; } } public class MyTimer{ public event EventHandler<MyEventArgs> Event; private void on(object source,EventArgs args){ if (Event != null){ MyEventArgs m = new MyEventArgs("myEventArgs"); Event(source, m);//发起事件 } } } class A{ public void play(object source,MyEventArgs args){ Console.Write("class A play called"+args.message); } public void let(ref int b){ Console.Write(b++); } }
ü 接口:类似于java的接口,使用interface声明,接口不能包含字段,接口可以有修饰符,接口成员默认是隐式public不允许有修饰符;如果类实现接口就必须实现接口中的所有成员,如果类要继承父类在实现接口,那么父类就必须放在最前面
ü 接口是引用类型:意味着可以把一个实现接口的类转化为接口,再调用接口的方法:MyClasslet=new MyClass();my a=(my)let;a.play();->(获取接口对象的引用),另外一种方法就是使用as来避免调用为空的异常(强制转化类未实现的接口的引用的时候会抛出异常):mya=let as my;if(a!=null)………;可以实现多个接口,实现包含多个具有重复成员的接口的时候-》类将实现单个成员来满足所有包含重复成员的接口;当类实现多个接口想要获得某个接口的引用的时候只需要写明接口的类型即可。
ü 派生类作为实现:如果基类写了接口的实现方法,但是没有实现接口,派生类继承了基类,实现了接口但是没有写实现接口的方法,那么接口还是算由基类实现的。
ü 接口可以继承接口:如 interface a:b,c
ü 转换:隐式转换(语言自动做的转换称为隐式转换->从更小的类型转换为更大的类型),强制转换:如ushort a=10;byteb=(byte)a;显示转换时会发生溢出现象C#提供checked和unchecked来检测结果溢出:如b=unchecked((byte)a)丢位不会抛出异常,b=checked((byte)a)如果溢出则抛出异常
ü 引用转换:子类A,父类B;A a=new A();Bb=(B)a;隐式引用转换:所有引用类型都可以被隐式的转换为object类型,所有引用类型都可以隐式的转换为它所继承的接口,所有引用类型都可以隐式的转换为(它所继承的任何类,任何接口)
ü 装箱和拆箱:想要将值类型放在堆上就要使用装箱操作:int a=10;object b=a;运行时在堆上创建一个包含值(5)的对象,b是对象的一个引用,该对象的值是原始值的一个副本,改变原始值不会改变箱内的值;
拆箱操作:inta=10;object b=a(隐式转换);int j=(int)b;
ü is和as:有些类型转换是不成功的,使用is来检测能否转换(A bill=new A();Person p;if(bill isPerson){p=bill;});使用as,它不抛出异常,如果转换失败则返回值为null;Person p=bill as Person;if(p==null){…}
ü 范型:从c#2.0开始微软引入了范性,c#提供了五种范性:类,结构,接口,委托和方法(成员);
ü 范性类和范性方法:
ü public class Fanxing { static void main(string[] args) { var a = new SomeClass<int, String>(); a.play("nihao"); } } class SomeClass<T1, T2>
whereT1:class//约束条件
whereT2:struct/new() { public T1 a; public T1(返回类型) play<T1,T1>(T2 b) { Console.WriteLine(b); return a; } }
ü 范性结构:
ü struct hello<T> { public T a; public hello(T value){ a = value; } public T Data { get{return a;} set{a=value;} } }
ü 范性委托:delegateR(返回类型) MyDelegate<T,R>(T value)
ü 范性接口:interfaceIMyfc<T>{T RetuenIt(T value);}
classsimple:IMyfc<int>,IMyfc<string>{..}->类型不同的两个接口
实现接口的时候必须保证类型实参数组合不会在类型中产生两个重复的接口。如class a<S>:Myfc<int>,Myfc<S>
ü 范性的协变和逆变:“协变”是指能够使用与原始指定的派生类型相比,派生程度更大的类型。“逆变”则是指能够使用派生程度更小的类型。协变和逆变可以应用于委托上;如Dog->Animal(协变)Animal->Dog(逆变)
ü 接口的协变和逆变:关键字:out(可协变)in(可逆变);如interface a(out T){T get();}->T是可协变的,应用于委托:delegate T Factory<out S,in T,M>()->对S支持协变,对T支持逆变,M不变。
ü 枚举数和迭代器:枚举数:实现IEnumerator/IEnumerable接口,实现IEnumerator<T>/IEnumerable<T>接口,不使用接口形式;如果是可枚举类型就可以直接使用foreach来进行迭代;
ü 使用IEnumerator接口:该接口有三个函数成员:Current(返回当前位置项属性),MoveNext(移动到下一位,成功->True,失败->False),Reset(将位置重制为开始的位置)
ü using System.Collections;
static void main(string[] args) { int[] a = new int[] { 1, 2, 3 }; IEnumerator ie = a.GetEnumerator(); while(ie.MoveNext()){ int i = (int)ie.Current; } ie.Reset(); }
ü 可以用类继承该接口实现其中的类;
ü IEnumerable接口:
using System.Collections;
class Myclass : IEnumerable
{
string[]color = { "red", "green", "black" };
publicIEnumerator GetEnumerator()
{
return new ColorEnumerator(color);
}
}
class ColorEnumerator: IEnumerator
{
publicstring[] color;
publicColorEnumerator(string[] color)
{
this.color = color;
}
publicobject Current() { }
publicbool MoveNext() { }
publicvoid Reset() { }
}
ü 可将接口写成范性
ü 使用迭代器来产生枚举数:
class Program
{
static void Main(string[] args)
{
Myclass1 mc = new Myclass1();
foreach (string i in mc)
{
Console.Write(i);
}
}
}
class Myclass
{
public IEnumerator<string>GetEnumerator()
{
return BlackAndWhite();
}
public IEnumerator<string>BlackAndWhite()//枚举数不会一次性返回所有的值,每次访问返回一个
{
yield return "black";//如果第一个满足则返回第一个
yield return "red";
yield return "green";
}
}
public class Myclass1
{
public IEnumerator<string>GetEnumerator()
{
IEnumerable<string> MyEnumerable= BlackAndWhite();
returnMyEnumerable.GetEnumerator();
}
public IEnumerable<string>BlackAndWhite()//产生枚举类型
{
yield return "black";
yield return "red";
yield return "yellow";
}
}
ü 异步编程介绍:同步编程:从程序第一句按照顺序执行到最后;异步编程:程序发起多个线程,理论上是在同一个时间执行的;对于同一个进程的多个线程来说,内存是可见也是可访问的。
ü 多线程处理的复杂度:线程之间的通信,协调线程,同步资源使用;
ü 并行循环:using System.Threading.Tasks,void Parallel.For(int form,intto,Action body)->开始,结束,body接受单个参数输入的委托;
ü static ParallelLoopResultForEach(IEnumerable<TSource>source,Action<TSource>body)->可迭代,行为
using System.Threading.Tasks;
static voidMain(string[] args)
{
int MaxSin = 10;
Myclass1 mc = new Myclass1();
int[] max = new int[MaxSin];
foreach (string i in mc)
{
//Console.Write(i);
}
Parallel.For(0, MaxSin, i =>{max[i]=i*i;});
foreach (int j in max)
{
Console.WriteLine(j);
}
string []s=newstring[]{"String","moajs","niahos"};
Parallel.ForEach(s, i =>Console.Write(string.Format("{0} has {1} letters ", i,i.Length)));
}
ü 预处理命令:预处理命令必须和c#代码在不同的行,预处理命令不需要以;结尾。
ü 编译符号只有两种可能性:要么被定义,要么没被定义;必须放在第一行;
#define;#undef;
ü 条件编译:#if,#else,#elif,#endif;如:#if a==0 a++; #elif a==1 a--;#endif
ü 诊断指令:#warning hahahhaha #errorhahhahaha
ü 行号指令:#line 3(编译器将执行第三行)#line “filename”(设置文件名)
#line default(重新保存实际的行号和文件名)
ü 区域指令:#region Constructor myclass{..} myclass(string s){..}#endregion
ü #pragma warning disable 618,404(关闭警告)#pragma warning restore618(开启警告)#pragma warning disable(关闭所有警告)#pragma warning restore(开启所有警告)
ü 元数据和反射:有关程序及其类型的数据被称为元数据,一个运行的程序查看本身的元数据或者其他程序的元数据的行为叫做反射。必须使用System.Reflection命名空间
Type类:Type成员:Name(类型的名字),Namespace(返回包含类型声明的命名空间)Assenbly(声明类型的程序集)GetFields(类型的字段列表)GetProperties(类型的属性列表)GetMethods(类型的方法列表)