目录
1. 特殊的数据成员........................................................................... 1
2. 数组(array)............................................................................. 1
3. 命名空间(namespace)................................................................. 2
4. 方法的参数传递........................................................................... 2
5. 构造器(constructor)................................................................. 3
6. 析构(Destructor)...................................................................... 4
7. 访问控制修饰符........................................................................... 5
8. 类型转换....................................................................................... 6
9. 属性(Property).......................................................................... 7
10. 索引器(indexer)....................................................................... 8
11. 委托(delegate)...................................................................... 10
12. 事件(event)............................................................................. 11
13. 虚方法(virtual)..................................................................... 13
14. 抽象类(abstract)................................................................... 14
15. 接口(interface).................................................................... 14
16. 排序(IComparable与IComparer)......................................... 17
17. 扩展方法................................................................................... 19
18. 密封类和密封方法(sealed).................................................... 20
19. yield return语句动态的返回集合....................................... 20
20. 多线程的应用........................................................................... 20
1.特殊的数据成员
(1) 常量const
定义方式:const int g = 10;
注意:常量的值必须在声明时初始化,常量的值不可变化,常量本身就是静态的不能使用static修饰。
(2) 只读字段readonly
定义方式:private readonly int t;
注意:只读字段必须在声明时或类构造方法中初始化,只读字段的值不可变化,只读字段不一定是静态的可以使用static修饰。
2.数组(array)
(1) 一维数组
定义方式:
int[] array=new int[num];
int[] array = { 1, 2, 3, 4, 5, 6 };
int[] array = new int[] { 1, 2, 3, 4, 5, 6 };
(2) 多维数组
定义方式:
int[,] array=new int[low,row];
int[,] array={{1,2},{5,6}};(一维的维度要一致)
int[,] array = new int[2,2]{{1,2},{5,6}};
(3) 不规则数组(数组的数组)
int[][] array=new int[3][];
array[0] = new int[] { 1, 2, 3, 4 };
array[1] = new int[] { 1, 2, 3};
array[2] = new int[] { 1, 2};
int[][,] array=new int[3][,];
(4) 数组遍历
遍历规则数组:
for (int i = 0; i < array.GetLength(0); i++)
{
for (int j = 0; j < array.GetLength(1); j++)
{
Console.Write(array[i,j] + " ");
}
Console.WriteLine();
}
遍历不规则数组:
for (int i = 0; i < array.Length; i++)
{
for (int j = 0; j < array[i].Length; j++)
{
Console.Write(array[i][j] + " ");
}
Console.WriteLine();
}
3.命名空间(namespace)
C#命名空间与Java的包一样,不同的程序文件里的类可以在同一命名空间里。命名空间可以嵌套。
4.方法的参数传递
(1) 值传递
代码形式:方法名称 (参数类型 参数名称)
说明:此方式并无特别之处。
(2) 引用参数(ref)
代码形式:方法名称 (ref 参数类型 参数名称)
说明:传递参数的引用可以改变原参数(实参),但是需要初始化实参。下面代码输出1。
class Program
{
static void add(ref int i)
{
i++;
}
static void Main(string[] args)
{
int i = 0;//必须先初始化
add(ref i);//调用时必须加ref
Console.WriteLine(i);
}
}
(3) 输出参数(out)
代码形式:方法名称 (out 参数类型 参数名称)
说明:传递参数的引用可以改变原参数(实参),但是在使用前需要初始化参数。下面代码输出100。
class Program
{
static void add(out int i)
{
i = 0;//必须在使用前初始化
i=100;
}
static void Main(string[] args)
{
int i;
add(out i);//调用时必须加out
Console.WriteLine(i);
}
}
(4) 传递可变数量的参数(params)
代码形式:方法名称 (params参数类型 参数名称)
说明:传递的参数数量不定,可以变化。下面的程序输出1 2 3。
class Program
{
static void Print(params int[] array)
{
foreach (int i in array)
{
Console.Write(i + " ");
}
}
static void Main(string[] args)
{
Print(1,2);
Print(3);
}
}
5.构造器(constructor)
(1) 创建对象的过程—无参构造器
class A
{
public A(int i){ }
}
class B : A
{ }
class Program
{
static void Main(string[] args)
{
new B();//无法创建对象
}
}
以上的程序无法创建B类对象,因为创建B类对象调用B类的默认构造器时会默认的调用其基类A的无参构造器,而A类却没有无参构造器,所以不能创建B类对象。
(2) 使用base调用基类构造器
class A
{
public A(int i) { }
}
class B : A
{
public B() : base(5) { }//调用A类的有参构造
}
class Program
{
static void Main(string[] args)
{
new B();//可以创建对象
}
}
(3) 静态构造器(Java中的静态初始化器)
静态构造器最多执行一次,执行在静态成员初始化完毕之后。下面程序输出20。
class Program
{
static void Main(string[] args)
{
Console.WriteLine(A.i);
}
}
class A
{
public static int i = 10;
static A()
{
i = 20;
}
}
6.析构(Destructor)
(1) 析构函数(Finalize操作)
下面程序运行结果:构造A构造A析构A析构A。
class Program
{
static void Main(string[] args)
{
new A();
new A();
}
}
class A
{
public A()
{
Console.Write("构造A");
}
~A()//析构
{
Console.Write("析构A");
}
}
(2) 在一般情况下不要实现析构函数,这会影响垃圾回收的性能。
(3) 显示调用垃圾回收:GC.Collect()会建议程序调用垃圾回收,微软强烈建议不要这样做!
(4) 释放模式,IDisposable接口
class A:IDisposable
{
private bool disposed = false;//标志是否已释放资源
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
Console.WriteLine("调用所引用的类的Dispose()方法!");
}
Console.WriteLine("调用类本身的非托管资源!");
disposed = true;
}
}
public void Dispose()
{
Dispose(true);//调用手动释放资源
GC.SuppressFinalize(this);//阻止调用终结器
}
~A()
{
Dispose(false);
}
}
对于下面主方法,执行结果:调用类本身的非托管资源!
class Program
{
static void Main(string[] args)
{
A a = new A();
}
}
对于下面主方法,执行结果:
调用所引用的类的Dispose()方法!
调用类本身的非托管资源!
class Program
{
static void Main(string[] args)
{
A a = new A();
a.Dispose();
a.Dispose();
}
}
(5) 对于继承了IDisposable接口的类,使用using简化try{}finally{}
对于下面的两个主方法,执行结果都是:
使用a对象
调用所引用的类的Dispose()方法!
调用类本身的非托管资源!
class Program
{
static void Main(string[] args)
{
A a = new A();
try
{ Console.WriteLine("使用a对象"); }
finally
{ a.Dispose(); }
}
}
class Program
{
static void Main(string[] args)
{
A a = new A();
using (a)//使用using
{
Console.WriteLine("使用a对象");
}
}
}
7.访问控制修饰符
(1) 修饰符的访问范围(空白表示不能访问)
访问控制修饰符 |
类内部 |
子类 |
程序集内 |
程序集外 |
default |
可以访问 |
|||
public |
可以访问 |
可以访问 |
可以访问 |
可以访问 |
private |
可以访问 |
|||
internal |
可以访问 |
可以访问 |
可以访问 |
|
protected |
可以访问 |
可以访问 |
||
protected internal |
可以访问 |
可以访问 |
可以访问 |
子类可以访问 |
(2) 总结:在C#1.0中,不声明任何修饰符,默认是私有的方法,也就是说default与private一样。当父类和子类在同一程序集时,子类可以访问父类的internal成员,当父类和子类不在同一程序集时,子类不可以访问父类的internal成员,但可以访问父类的protected interal成员。
8.类型转换
(1) 使用checked与unchecked检测抓换的异常(如:溢出)
下面程序会出现溢出异常,而中断执行。
class Program
{
static void Main(string[] args)
{
long a = 1000000000000;
int b;
b = checked((int)a);//使用checked检测是否溢出
}
}
下面程序会忽略溢出异常。
class Program
{
static void Main(string[] args)
{
long a = 1000000000000;
int b;
b = unchecked((int)a);//使用unchecked忽略溢出异常,默认也是忽略溢出异常
}
}
(2) 使用is判断类型
下面程序的执行结果:True False True True
class A
{ }
class B:A
{ }
class Program
{
static void Main(string[] args)
{
A a = new A();
B b = new B();
Console.WriteLine(a is A);
Console.WriteLine(a is B);
Console.WriteLine(b is A);
Console.WriteLine(b is B);
}
}
(3) 使用as操作符(使用as比is效率高)
class A
{ }
class B:A
{ }
class Program
{
static void Main(string[] args)
{
A a = new A();
B b = a as B;//转换失败返回null
if (a != null)
{
Console.WriteLine("转换成功");
}
}
}
9.属性(Property)
(1) 使用属性访问私有成员
class A
{
private string m_name;
public string Name
{
get
{ return m_name; }
set
{
if (value!=null)//赋值前的处理
m_name = value;
}
}
}
class Program
{
static void Main(string[] args)
{
A a = new A();
a.Name = "lizhiwei";
Console.WriteLine(a.Name);
}
}
(2) 访问静态成员的属性
class A
{
private static int m_num=0;
public A()
{
m_num++;
}
public static int Num
{
get
{ return m_num; }
}
}
class Program
{
static void Main(string[] args)
{
new A();
Console.WriteLine(A.Num);
new A();
Console.WriteLine(A.Num);
}
}
10.索引器(indexer)
(1) 使用索引器
下面程序运行结果:1 2
class A
{
private int[] array=new int[20];
public int this[int index]//索引器
{
get
{ return array[index]; }
set
{ array[index] = value; }
}
}
class Program
{
static void Main(string[] args)
{
A a = new A();
a[0] = 1;//访问索引器set
a[19] = 2;//访问索引器set
Console.WriteLine(a[0] + " " + a[19]);//访问索引器get
}
}
(2) 索引器的重载
下面的程序运行结果:lizhiwei li
class A
{
private Hashtable m_map = new Hashtable();
public string this[string key]//索引器
{
get
{ return m_map[key].ToString(); }
set
{ m_map[key] = value; }
}
public string this[int key]//重载索引器
{
get
{ return m_map[key].ToString(); }
set
{ m_map[key] = value; }
}
}
class Program
{
static void Main(string[] args)
{
A a = new A();
a["001"] = "lizhiwei";
a[2] = "li";
Console.WriteLine(a["001"]+" "+a[2]);
}
}
(3) 多参数的索引器
下面程序运行结果:20 10
class A
{
private string m_name;
private int m_age;
private string m_sex;
public string Name
{
get
{ return m_name; }
set
{ m_name = value; }
}
public int Age
{
get
{ return m_age; }
set
{ m_age = value; }
}
public string Sex
{
get
{ return m_sex; }
set
{ m_sex=value; }
}
}
class B
{
private ArrayList m_list = new ArrayList();
public int this[string name, string sex]
{
get
{
foreach (A a in m_list)
{
if (a.Name.Equals(name) && a.Sex.Equals(sex))
{
return a.Age;
}
}
return -1;
}
set
{
A a=new A();
a.Name=name;
a.Sex=sex;
a.Age=value;//value的类型与返回值类型一致(这里是int)
m_list.Add(a);
}
}
}
class Program
{
static void Main(string[] args)
{
B b = new B();
b["李志伟", "男"] = 20;
b["张三", "男"] = 10;
Console.Write(b["李志伟", "男"]+" "+b["张三", "男"]);
}
}
(4) 注意:索引器不能是静态(static)的!
11.委托(delegate)
(1) 委托的使用(类似指向函数的指针)
下面程序运行结果:李志伟
delegate void PrintDelegate(string s);//申明委托
class A
{
public void Print(string s)//与委托的返回值、参数相同的函数
{
Console.WriteLine(s);
}
}
class Program
{
static void Main(string[] args)
{
A a = new A();
PrintDelegate s=new PrintDelegate(a.Print);//新建委托链
s("李志伟");//执行委托连
}
}
(2) 委托链的使用
下面程序的运行结果:
a1李志伟 a2李志伟 a2李志伟
a1李志伟 a2李志伟
delegate void PrintDelegate(string s);//申明委托
class A
{
private string name;
public A(string name)
{
this.name = name;
}
public void Print(string s)//与委托的返回值、参数相同的函数
{
Console.Write(name+s+" ");
}
}
class Program
{
static void Main(string[] args)
{
A a1 = new A("a1");
A a2 = new A("a2");
PrintDelegate s=new PrintDelegate(a1.Print);//新建委托链
s += new PrintDelegate(a2.Print);//增加委托链
s += new PrintDelegate(a2.Print);//增加委托链
s("李志伟");//执行委托链
Console.WriteLine();
s -= new PrintDelegate(a2.Print);//减少委托链
s("李志伟");//执行委托链
}
}
(3) 直接使用委托调用匿名方法
delegate void PrintDelegate(string s);//申明委托
class Program
{
static void Main(string[] args)
{
PrintDelegate s=null;
s += delegate(string temp) { Console.WriteLine(temp); };//委托指向匿名方法
s("李志伟");//执行委托连
}
}
(4) 使用Action<T>与Func<in T,out TResult>省略委托的定义
当委托没有返回值时使用Action<T>,有返回值时使用Func<in T,out TResult>。例如:
class Program
{
private void Hello(string name)//无返回值
{
Console.WriteLine("你好,"+name+"!");
}
private string GETAge(int age)//有返回值
{
Console.WriteLine("我的年龄:" + age + "!");
return "我的年龄:" + age + "!";
}
static void Main(string[] args)
{
Program p = new Program();
Action<string> action = p.Hello;
//Action<string> hello = new Action<string>(p.Hello);
action("李志伟");//执行委托
Func<int, string> fun = p.GETAge;
Console.WriteLine(fun(20));//执行委托
}
}
(5) Lambda表达式,方便的使用匿名方法
class Program
{
static void Main(string[] args)
{
//标准的Lambda格式
Func<int, int, string> sum = (int a, int b) => { return "和是:" + (a + b); };
Console.WriteLine(sum(5, 6));//和是:11
//简写格式
Action<string> action = param => Console.WriteLine(param);//委托匿名方法
action("调用委托");
Func<int, Double> func = param => param * param;//有返回值的匿名方法
Console.WriteLine(func(5));//25,调用委托返回25
}
}
12.事件(event)
(1) 实现事件委托的原理
下面的程序运行的结果:
事件被触发,执行事件委托链!
执行触发事件执行的方法!
执行触发事件执行的方法!
class A
{
public delegate void Publish();//事件方法的委托
public event Publish OnPublish;//事件委托链
public void OnEvent()//触发事件,执行事件委托链
{
if (OnPublish != null)//事件委托链不为null
{
Console.WriteLine("事件被触发,执行事件委托链!");
OnPublish();//执行事件委托链
}
}
public void Event()//触发事件执行的方法
{
Console.WriteLine("执行触发事件执行的方法!");
}
}
class Program
{
static void Main(string[] args)
{
A a = new A();
a.OnPublish += new A.Publish(a.Event);//订阅(注册)事件,本质是增加委托链
a.OnPublish += new A.Publish(a.Event);//订阅(注册)事件,本质是增加委托链
a.OnEvent();//触发事件,执行事件委托链
}
}
(2) .NET Framework事件设计准则
申明delegate时,使用void类型当做返回值,EventName事件的事件委托时EventNameEventHandler,事件接受两个传入参数,一律命名sender与e。定义一个提供事件数据的类,对类EventNameEventArgs进行命名,从System.EventArgs派生该类,然后添加所有事件特定的成员。
//包含事件数据的类,命名方式:EventNameEventArgs
class AEventArgs : EventArgs
{
private readonly string name;//只读属性
public AEventArgs(string name)
{
this.name = name;
}
public string Name
{
get
{ return name; }
}
}
//引发事件的类
class B
{
//事件方法的委托,命名方式EventNameEventHandler
public delegate void PublishEventHandler(object sender,AEventArgs e);
//事件委托链
public event PublishEventHandler Publish;
//引发执行事件委托链的方法,命名方式:OnEventName
protected virtual void OnEvent(AEventArgs e)
{
PublishEventHandler handler = Publish;
if (handler != null)
{
handler(this,e);
}
}
//触发事件的方法
public void TriggerEvent(string name)
{
Console.WriteLine("事件被触发!!!");
//调用引发执行事件委托链的方法
OnEvent(new AEventArgs(name));
}
//事件处理的方法
public void HandlingEvents(object sender, AEventArgs e)
{
Console.WriteLine(e.Name+" 处理事件!!!");
}
}
class Program
{
static void Main(string[] args)
{
B b = new B();
//订阅(注册)事件,本质是增加委托链
b.Publish += new B.PublishEventHandler(b.HandlingEvents);
b.TriggerEvent("李志伟");
}
}
上面的程序使用了.NET Framework事件设计准则,运行结果:
事件被触发!!!
李志伟 处理事件!!!
13.虚方法(virtual)
(1) 使用new隐藏基类方法
下面的程序运行结果:A.print B.print
class A
{
public void print()
{
Console.WriteLine("A.print");
}
}
class B : A
{
public new void print()//使用new显示的隐藏基类相同方法
{
Console.WriteLine("B.print");
}
}
class Program
{
static void Main(string[] args)
{
B b = new B();
A a = b;
a.print();//A.print
b.print();//B.print
}
}
(2) 使用virtual与override覆盖基类方法(实现了多态)
下面程序运行结果:B.print B.print
class A
{
public virtual void print()//使用virtual申明虚方法
{
Console.WriteLine("A.print");
}
}
class B : A
{
public override void print()//使用override覆盖基类虚方法
{
Console.WriteLine("B.print");
}
}
class Program
{
static void Main(string[] args)
{
B b = new B();
A a = b;
a.print();//B.print
b.print();//B.print
}
}
14.抽象类(abstract)
(1)抽象类的使用
abstract class A
{
protected string m_name;
public abstract void print();//抽象方法
public abstract string Name//抽象属性,也可使用抽象索引器
{
set;
get;
}
}
class B : A
{
public override void print()//必须使用override或new,否则报错
{
Console.WriteLine(base.m_name);
}
public override string Name//必须使用override或new,否则报错
{
set{ base.m_name=value;}
get{ return base.m_name;}
}
}
class Program
{
static void Main(string[] args)
{
B b = new B();
b.Name = "李志伟";
b.print();
}
}
(2)不能有静态(static)的抽象方法,也不能有静态的抽象属性!
15.接口(interface)
(1)接口的使用
interface IA
{
void print();//抽象方法,不能使用public等修饰符
string Name//抽象属性,也可使用抽象索引器
{
set;
get;
}
}
class B : IA
{
private string m_name;
public void print()//不能使用override或new
{
Console.WriteLine(m_name);
}
public string Name//不能使用override或new
{
set{ m_name=value;}
get{ return m_name;}
}
}
class Program
{
static void Main(string[] args)
{
B b = new B();
b.Name = "李志伟";
b.print();
}
}
(2)接口里不能包含成员变量、构造器、析构器,接口的抽象方法不能使用修饰符(如:abstract、public等),因为抽象方法必须是public abstract。
(3)使用完全限定接口成员名(显示接口成员实现)
interface IA
{
void print();
}
interface IB
{
void print();
}
class A:IA,IB
{
void IA.print()//显示接口成员实现,不能使用public等关键字,只能是private
{
Console.WriteLine("IA.print");
}
void IB.print()//显示接口成员实现,不能使用public等关键字,只能是private
{
Console.WriteLine("IB.print");
}
public void print()
{
Console.WriteLine("A.print");
}
}
class Program
{
static void Main(string[] args)
{
A a = new A();
((IA)a).print();//使用IA接口访问,IA的print()
((IB)a).print();//使用IB接口访问,IB的print()
a.print();//只能访问自己的print()
}
}
上面程序运行结果:IA.print IB.print A.print
(4)接口的复杂使用(复杂的多重继承)
(a)直观隐藏规则
interface IA
{
void F();
}
interface IB : IA
{
new void F();//隐藏了IA的F()
}
interface IC : IA
{
void G();
}
interface IBC : IB, IC
{
}
class Test : IBC
{
public void F()
{
Console.WriteLine("IB.F");//由于IB隐藏了IA的F(),所以这里实现的是IB的F()
}
public void G()
{
Console.WriteLine("IC.G");
}
}
class Program
{
static void Main(string[] args)
{
Test t = new Test();
t.F();
((IA)t).F();
((IB)t).F();
((IC)t).F();//值得注意,由于IB隐藏了IA的F(),所以这里调用的是IB的F()
((IBC)t).F();
}
}
上面程序运行结果:IB.F IB.F IB.F IB.F IB.F
(b)接口的重新实现
interface IA
{
void print();
}
class A : IA
{
void IA.print()//接口的继承
{
Console.WriteLine("A.print");
}
}
class B:A,IA
{
public void print()//接口的重新实现,将会覆盖接口的继承,所以A的print()被完全覆盖
{
Console.WriteLine("B.print");
}
}
class Program
{
static void Main(string[] args)
{
B b = new B();
((IA)b).print();
}
}
上面程序运行结果:B.print
16.排序(IComparable与IComparer)
(1)基本数据类型的排序
class Program
{
static void Main(string[] args)
{
int[] array = {2,3,6,9,8,4,7,5,0};
Array.Sort(array);//排序方法
foreach(int i in array)
{
Console.Write(i+" ");
}
}
}
上面的程序运行结果:0 2 3 4 5 6 7 8 9
(2)自定义的类型的排序(实现IComparable接口)
class A:IComparable
{
private string name;
private int age;
public A(string name, int age)
{
this.name = name;
this.age = age;
}
public int CompareTo(object obj)//实现比较的方法
{
A temp;
if(obj is A)
{
temp=obj as A;
}
else
{
throw new ArgumentException("类型不一致!");
}
return this.name.CompareTo(temp.name);//根据姓名排序
}
public override string ToString()
{
return "[" + name + " " + age + "]";
}
}
class Program
{
static void Main(string[] args)
{
A[] array =new A[3];
array[0] = new A("李志伟",20);
array[1] = new A("张三", 19);
array[2] = new A("李四", 17);
Array.Sort(array);//排序方法,对自定义类型进行排序
foreach(A i in array)
{
Console.Write(i+" ");
}
}
}
(3)为自定义的类定义排序类(IComparer接口)
class A
{
private string name;
private int age;
public A(string name, int age)
{
this.name = name;
this.age = age;
}
public string Name
{
get { return name; }
}
public int Age
{
get { return age; }
}
public override string ToString()
{
return "[" + name + " " + age + "]";
}
}
class B : IComparer//专为类A设计的排序类
{
private static B b;
private B()
{
}
public static B GetB()
{
if (b == null)
{
b = new B();
}
return b;
}
public int Compare(Object x, Object y)//实现排序方法
{
A xa, ya;
if ((x is A) && (y is A))
{
xa = x as A;
ya = y as A;
}
else
{
throw new ArgumentException("类型不一致!");
}
return xa.Name.CompareTo(ya.Name);//根据姓名排序
}
}
class Program
{
static void Main(string[] args)
{
A[] array =new A[3];
array[0] = new A("李志伟",20);
array[1] = new A("张三", 19);
array[2] = new A("李四", 17);
Array.Sort(array,B.GetB());//排序方法
foreach(A i in array)
{
Console.Write(i+" ");
}
}
}
17.扩展方法
(1)说明:
通过扩展方法,我们可以对已有类型做自己想做的相关扩展而不需要已有类型的源代码。扩展方法是通过额外的静态方法扩展现有的类型。也可以对String,Int,DataTable等类型的基础上增加一个或多个方法,使用时不需要去修改或编译类型本身的代码。
(2)例子:
public static class MyExtensions//静态的扩展类
{
public static int StringExtensions(this String str)//为String类增加一个方法
{
Console.WriteLine(str);
return str.Length;
}
public static String StringJoin(this String str1,String str2)//为String类增加一个方法
{
Console.WriteLine(str1+str2);
return str1 + str2;
}
}
class Program
{
static void Main(string[] args)
{
String s = "12345678";
s.StringExtensions();//测试自定义的扩展方法
s.StringJoin("000000000000000");//测试自定义的扩展方法
}
}
(3)注意:
如果扩展方法包含参数,就可以在要扩展的类型(即第一个参数)以后顺序的添加扩展方法对应的参数既可,在调用的时候填写相应参数,不过请记住,第一个参数是要扩展的类型,其前面要加this关键字,在填写实参的时候并没有这个参数。
18.密封类和密封方法(sealed)
(1)Sealed修饰类不能被继承,sealed修饰方法不能被重写,类似Java的Final关键字。
19.yield return语句动态的返回集合
class Program
{
static IEnumerable<string> GetEnumerator(int a, int b)
{
long d = 1;
for (int i = 1; i <= b; i++)
{
d = a * d;
yield return a + "的" + i + "次方是:" + d;//多次被执行
}
}
static void Main(string[] args)
{
foreach (string s in GetEnumerator(2,20))//遍历返回的集合
{
Console.WriteLine(s);
}
}
}
20.多线程的应用
(1)多线程的基本使用
不需要传递参数,也不需要返回参数:
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 30; i++)
{
ThreadStart threadStart = new ThreadStart(Calculate);
Thread thread = new Thread(threadStart);
thread.Start();
}
Thread.Sleep(2000);
Console.Read();
}
public static void Calculate()
{
DateTime time = DateTime.Now;//得到当前时间
Random ra = new Random();//随机数对象
Thread.Sleep(ra.Next(10,100));//随机休眠一段时间
Console.WriteLine(time.Minute + ":" + time.Millisecond);
}
}
ThreadStart是一个委托,这个委托的定义为void ThreadStart(),没有参数与返回值。
需要传递单个参数:
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 30; i++)
{
ParameterizedThreadStart tStart = new ParameterizedThreadStart(Calculate);
Thread thread = new Thread(tStart);
thread.Start(i*10+10);//传递参数
}
Thread.Sleep(2000);
Console.Read();
}
public static void Calculate(object arg)
{
Random ra = new Random();//随机数对象
Thread.Sleep(ra.Next(10, 100));//随机休眠一段时间
Console.WriteLine(arg);
}
}
ParameterThreadStart委托定义为void ParameterizedThreadStart(object state),有一个参数但是没有返回值。
使用专门的线程类:
class Program
{
static void Main(string[] args)
{
MyThread mt = new MyThread(100);
ThreadStart threadStart = new ThreadStart(mt.Calculate);
Thread thread = new Thread(threadStart);
thread.Start();
//等待线程结束
while (thread.ThreadState != ThreadState.Stopped)
{
Thread.Sleep(10);
}
Console.WriteLine(mt.Result);//打印返回值
Console.Read();
}
}
public class MyThread//线程类
{
public int Parame { set; get; }//参数
public int Result { set; get; }//返回值
//构造函数
public MyThread(int parame)
{
this.Parame = parame;
}
//线程执行方法
public void Calculate()
{
Random ra = new Random();//随机数对象
Thread.Sleep(ra.Next(10, 100));//随机休眠一段时间
Console.WriteLine(this.Parame);
this.Result = this.Parame * ra.Next(10, 100);
}
}
使用线程类可以有多个参数与多个返回值,十分灵活!
使用匿名方法:
class Program
{
static void Main(string[] args)
{
int Parame = 100;//当做参数
int Result = 0;//当做返回值
//匿名方法
ThreadStart threadStart = new ThreadStart(delegate()
{
Random ra = new Random();//随机数对象
Thread.Sleep(ra.Next(10, 100));//随机休眠一段时间
Console.WriteLine(Parame);//输出参数
Result = Parame * ra.Next(10, 100);//计算返回值
});
Thread thread = new Thread(threadStart);
thread.Start();//多线程启动匿名方法
//等待线程结束
while (thread.ThreadState != ThreadState.Stopped)
{
Thread.Sleep(10);
}
Console.WriteLine(Result);//打印返回值
Console.Read();
}
}
使用匿名方法启动线程可以有多个参数和返回值,而且使用非常方便!
(2)如何判断线程已经运行完成
使用System.Threading.ThreadState枚举判断线程状态,与Thread.ThreadState 属性配合使用。