1. 上篇
C# 泛型 (OK)
C# 匿名方法 (OK)
C# 委托 (OK)
C# 集合 (OK)
C# 索引器 (OK)
C# 事件 (OK)
C# 属性 (OK)
2. 下篇
C# 特性
C# 反射
C# 不安全代码
C# 多线程
C# 泛型
泛型
泛型允许推迟类或方法中编程元素的数据类型规范的编写,直到实际在程序中使用它的时候再编写。换句话说,泛型允许编写一个可以与任何数据类型协作的类或方法。
你可以通过数据类型的替代参数来编写类或方法的规范。当编译器遇到类的构造函数或方法的函数调用时,它会生成代码来处理指定的数据类型。下面这个简单的示例将有助于理解这个概念:
using System;
using System.Collections.Generic;
namespace GenericApplication
{
public class MyGenericArray<T>
{
private T[] array;
public MyGenericArray(int size)
{
array = new T[size + 1];
}
public T getItem(int index)
{
return array[index];
}
public void setItem(int index, T value)
{
array[index] = value;
}
}
class Tester
{
static void Main(string[] args)
{
// 声明一个整型数组
MyGenericArray<int> intArray = new MyGenericArray<int>(5);
// 设置值
for (int c = 0; c < 5; c++)
{
intArray.setItem(c, c*5);
}
// 获取值
for (int c = 0; c < 5; c++)
{
Console.Write(intArray.getItem(c) + " ");
}
Console.WriteLine();
// 声明一个字符数组
MyGenericArray<char> charArray = new MyGenericArray<char>(5);
// 设置值
for (int c = 0; c < 5; c++)
{
charArray.setItem(c, (char)(c+97));
}
// 获取值
for (int c = 0; c< 5; c++)
{
Console.Write(charArray.getItem(c) + " ");
}
Console.WriteLine();
Console.ReadKey();
}
}
}
编译执行上述代码,得到如下结果:
0 5 10 15 20
a b c d e
泛型的特性
泛型是一种可以增强程序功能的技术,表现在如下几个方面:
- 它有助于最大限度地进行重用代码、确保类型的安全以及提高性能。
- 你可以创建泛型集合类。.NET 框架类库在 System.Collections.Generic 命名空间中包含了一些新的泛型集合类,你可以使用这些泛型集合类来替代 System.Collections 中的集合类。
- 你可以创建自己的泛型接口、泛型类、泛型方法、泛型事件和泛型委托。
- 你可以对泛型类进行约束,使其只访问具有特定数据类型的方法。
- 在运行时,通过使用反射方法可以获取泛型数据类型中所使用的类型信息。
泛型方法
在之前的例子中,我们使用过一个泛型类,我们还可以通过类型参数来声明泛型方法。下述示例很好地展示了这个概念:
using System;
using System.Collections.Generic;
namespace GenericMethodAppl
{
class Program
{
static void Swap<T>(ref T lhs, ref T rhs)
{
T temp;
temp = lhs;
lhs = rhs;
rhs = temp;
}
static void Main(string[] args)
{
int a, b;
char c, d;
a = 10;
b = 20;
c = 'I';
d = 'V';
// 显示交换之前的值
Console.WriteLine("Int values before calling swap:");
Console.WriteLine("a = {0}, b = {1}", a, b);
Console.WriteLine("Char values before calling swap:");
Console.WriteLine("c = {0}, d = {1}", c, d);
// 调用 swap 进行交换
Swap<int>(ref a, ref b);
Swap<char>(ref c, ref d);
// 显示交换之后的值
Console.WriteLine("Int values after calling swap:");
Console.WriteLine("a = {0}, b = {1}", a, b);
Console.WriteLine("Char values after calling swap:");
Console.WriteLine("c = {0}, d = {1}", c, d);
Console.ReadKey();
}
}
}
编译执行上述代码,得到如下结果:
Int values before calling swap:
a = 10, b = 20
Char values before calling swap:
c = I, d = V
Int values after calling swap:
a = 20, b = 10
Char values after calling swap:
c = V, d = I
泛型委托
你可以通过类型参数来定义一个泛型委托,如:
delegate T NumberChanger<T>(T n);
泛型委托示例:
using System;
using System.Collections.Generic;
delegate T NumberChanger<T>(T n);
namespace GenericDelegateAppl
{
class TestDelegate
{
static int num = 10;
public static int AddNum(int p)
{
num += p;
return num;
}
public static int MultNum(int q)
{
num *= q;
return num;
}
public static int getNum()
{
return num;
}
static void Main(string[] args)
{
// 创建委托实例
NumberChanger<int> nc1 = new NumberChanger<int>(AddNum);
NumberChanger<int> nc2 = new NumberChanger<int>(MultNum);
// 使用委托对象调用方法
nc1(25);
Console.WriteLine("Value of Num: {0}", getNum());
nc2(5);
Console.WriteLine("Value of Num: {0}", getNum());
Console.ReadKey();
}
}
}
编译执行以上代码,得到如下结果:
Value of Num: 35
Value of Num: 175
C# 匿名方法
匿名方法
先前的章节中提过,委托是用于引用与其具有相同签名的方法,即使用委托对象,就可以调用任何被该委托引用的方法。
匿名方法提供了一种将一段代码块作为委托参数的技术。顾名思义,匿名方法没有名字,只有方法主体。
你不需要为匿名方法指定返回类型,其返回类型直接由方法主体推断而来。
编写匿名方法
匿名方法通过使用 delegate 关键字创建委托实例来实现方法的声明,如:
delegate void NumberChanger(int n);
...
NumberChanger nc = delegate(int x)
{
Console.WriteLine("Anonymous Method: {0}", x);
};
上述代码块中的 Console.WriteLine("Anonymous Method: {0}", x); 就是匿名方法的主体。
委托可以通过匿名方法调用,也可以通过命名方法调用,即,通过向委托对象来传递方法参数,如:
nc(10);
示例
using System;
delegate void NumberChanger(int n);
namespace DelegateAppl
{
class TestDelegate
{
static int num = 10;
public static void AddNum(int p)
{
num += p;
Console.WriteLine("Named Method: {0}", num);
}
public static void MultNum(int q)
{
num *= q;
Console.WriteLine("Named Method: {0}", num);
}
public static int getNum()
{
return num;
}
static void Main(string[] args)
{
//使用匿名方法创建委托实例
NumberChanger nc = delegate(int x)
{
Console.WriteLine("Anonymous Method: {0}", x);
};
//使用匿名方法调用委托
nc(10);
//使用命名方法实例化委托
nc = new NumberChanger(AddNum);
//使用命名方法调用委托
nc(5);
//使用另一个命名方法实例化委托
nc = new NumberChanger(MultNum);
//使用另一个命名方法调用委托
nc(2);
Console.ReadKey();
}
}
}
编译执行上述代码,得到如下结果:
Anonymous Method: 10
Named Method: 15
Named Method: 30
C# 委托
委托
C# 中的委托类似于 C 或 C++ 中指向函数的指针。委托表示引用某个方法的引用类型变量,运行时可以更改引用对象。
特别地,委托可以用于处理事件或回调函数。并且,所有的委托类都是从 System.Delegate 类继承而来。
声明委托
声明委托时,需要定义能够被委托所引用的方法,任意委托可以引用与该委托拥有相同签名的方法。如:
public delegate int MyDelegate (string s);
上述委托可以用于引用任何一个以字符型为参数的方法,且返回值类型为整型。
声明委托的句法规则为:
delegate <return type> <delegate-name> <parameter list>
实例化委托
声明委托之后,必须使用 new 关键字和一个特定的方法来创建一个委托对象。创建时,传递到 new 语句的参数写法与方法调用相同,但是不带有参数,例如:
public delegate void printString(string s);
...
printString ps1 = new printString(WriteToScreen);
printString ps2 = new printString(WriteToFile);
下述示例演示了委托的声明、实例化,此处的委托用于引用一个带有一个整型参数的方法,且该方法返回一个整型值。
using System;
delegate int NumberChanger(int n);
namespace DelegateAppl
{
class TestDelegate
{
static int num = 10;
public static int AddNum(int p)
{
num += p;
return num;
}
public static int MultNum(int q)
{
num *= q;
return num;
}
public static int getNum()
{
return num;
}
static void Main(string[] args)
{
// 创建委托实例
NumberChanger nc1 = new NumberChanger(AddNum);
NumberChanger nc2 = new NumberChanger(MultNum);
// 使用委托对象调用方法
nc1(25);
Console.WriteLine("Value of Num: {0}", getNum());
nc2(5);
Console.WriteLine("Value of Num: {0}", getNum());
Console.ReadKey();
}
}
}
编译执行上述代码,得到如下结果:
Value of Num: 35
Value of Num: 175
委托的多播
委托对象可通过 "+" 运算符进行合并。一个合并委托可以调用它所合并的两个委托,但只有相同类型的委托可被合并。"-" 运算符则可用于从合并的委托中移除其中一个委托。
利用委托的这种特性,可以创建一个委托被调用时所涉及的方法的调用列表。这被称为委托的多播,也叫组播。下面的程序演示了委托的多播:
using System;
delegate int NumberChanger(int n);
namespace DelegateAppl
{
class TestDelegate
{
static int num = 10;
public static int AddNum(int p)
{
num += p;
return num;
}
public static int MultNum(int q)
{
num *= q;
return num;
}
public static int getNum()
{
return num;
}
static void Main(string[] args)
{
// 创建委托实例
NumberChanger nc;
NumberChanger nc1 = new NumberChanger(AddNum);
NumberChanger nc2 = new NumberChanger(MultNum);
nc = nc1;
nc += nc2;
// 调用多播
nc(5);
Console.WriteLine("Value of Num: {0}", getNum());
Console.ReadKey();
}
}
}
编译执行上述代码,得到如下结果:
Value of Num: 75
委托的使用
下面的示例演示了委托的作用,示例中的 printString 委托可用于引用带有一个字符串作为输入的方法,且不返回数据。
我们使用这个委托来调用两个方法,第一个方法将字符串输出到控制台,第二个方法将字符串输出到文件:
using System;
using System.IO;
namespace DelegateAppl
{
class PrintString
{
static FileStream fs;
static StreamWriter sw;
// 委托声明
public delegate void printString(string s);
// 该方法打印到控制台
public static void WriteToScreen(string str)
{
Console.WriteLine("The String is: {0}", str);
}
// 该方法打印到文件
public static void WriteToFile(string s)
{
fs = new FileStream("c:\\message.txt",
FileMode.Append, FileAccess.Write);
sw = new StreamWriter(fs);
sw.WriteLine(s);
sw.Flush();
sw.Close();
fs.Close();
}
// 该方法把委托作为参数,并使用它调用方法
// call the methods as required
public static void sendString(printString ps)
{
ps("Hello World");
}
static void Main(string[] args)
{
printString ps1 = new printString(WriteToScreen);
printString ps2 = new printString(WriteToFile);
sendString(ps1);
sendString(ps2);
Console.ReadKey();
}
}
}
编译执行上述代码,得到如下结果:
The String is: Hello World
C# 集合
集合
集合类专门用于数据存储和数据检索,并提供堆栈、队列、列表和哈希表的支持。目前,大多数集合类都实现了相同的接口。
集合类服务于不同的目的,如为元素动态分配内存,基于索引访问列表项等等,这些类所创建的是 Object 类的对象的集合。在 C# 中,Object 类是所有数据类型的基类。
各种集合类及其用法
下表为一些常用的以 System.Collection 为命名空间的集合类,点击相应链接,可查看详细说明。
类 | 描述及用法 |
---|---|
动态数组 | 动态数组表示可被单独索引的对象的有序集合。 动态数组基本上可以替代数组,但与数组不同的是,通过索引,动态数组可以在指定的位置添加和移除项目,且会自动重新调整大小,同样允许在列表中进行动态内存分配、增加、搜索、排序各项。 |
哈希表 | 哈希表使用键来访问集合中的元素。 当需要通过键访问元素时,则使用哈希表,且一个有用的键值可以很方便地被识别。哈希表中的每一项都有一个键/值对。键用于访问集合中的项目。 |
排序列表 | 排序列表使用键和索引来访问列表中的项。 它是数组和哈希表的组合,包含一个可使用键或索引访问各项的列表。若使用索引来访问各项,则它为一个动态数组,若使用键来访问各项,则它为一个哈希表。集合中的各项总是按键值排序。 |
堆栈 | 堆栈表示的是一个后进先出的对象集合。 当需要对各项进行后进先出的访问时,则使用堆栈。在列表中添加一项,称为推入元素;从列表中移除一项时,称为弹出元素。 |
队列 | 队列表示的是一个先进先出的对象集合。 当需要对各项进行先进先出的访问时,则使用队列。在列表中添加一项,称为入队;从列表中移除一项,称为出队。 |
点阵列 | 点阵列表示的是一个使用值 1 和 0 来表示的二进制数组。 当需要存储位,但事先不知道位数时,则使用点阵列。通过整型索引,可以从点阵列集合中访问各项,该索引值从零开始。 |
C# 索引器
索引器
创建索引器可以使一个对象像数组一样被索引。为类定义索引器时,该类的行为类似于一个虚拟数组,使用数组访问运算符([ ])则可以对该类来进行访问。
句法规则
创建一个一维索引器的规则如下:
element-type this[int index]
{
// get 访问器
get
{
// 返回 index 指定的值
}
// set 访问器
set
{
// 设置 index 指定的值
}
}
使用索引器
索引器的声明在某种程度上类似于属性的声明,例如,使用 get 和 set 方法来定义一个索引器。不同的是,属性值的定义要求返回或设置一个特定的数据成员,而索引器的定义要求返回或设置的是某个对象实例的一个值,即索引器将实例数据切分成许多部分,然后通过一些方法去索引、获取或是设置每个部分。
定义属性需要提供属性名,而定义索引器需要提供一个指向对象实例的 this 关键字。
示例:
using System;
namespace IndexerApplication
{
class IndexedNames
{
private string[] namelist = new string[size];
static public int size = 10;
public IndexedNames()
{
for (int i = 0; i < size; i++)
namelist[i] = "N. A.";
}
public string this[int index]
{
get
{
string tmp;
if( index >= 0 && index <= size-1 )
{
tmp = namelist[index];
}
else
{
tmp = "";
}
return ( tmp );
}
set
{
if( index >= 0 && index <= size-1 )
{
namelist[index] = value;
}
}
}
static void Main(string[] args)
{
IndexedNames names = new IndexedNames();
names[0] = "Zara";
names[1] = "Riz";
names[2] = "Nuha";
names[3] = "Asif";
names[4] = "Davinder";
names[5] = "Sunil";
names[6] = "Rubic";
for ( int i = 0; i < IndexedNames.size; i++ )
{
Console.WriteLine(names[i]);
}
Console.ReadKey();
}
}
}
编译执行上述代码,得到如下结果:
Zara
Riz
Nuha
Asif
Davinder
Sunil
Rubic
N. A.
N. A.
N. A.
重载索引器
索引器允许重载,即允许使用多种不同类型的参数来声明索引器。索引值可以是整数,但也可以是其他的数据类型,如字符型。
重载索引器示例:
using System;
namespace IndexerApplication
{
class IndexedNames
{
private string[] namelist = new string[size];
static public int size = 10;
public IndexedNames()
{
for (int i = 0; i < size; i++)
{
namelist[i] = "N. A.";
}
}
public string this[int index]
{
get
{
string tmp;
if( index >= 0 && index <= size-1 )
{
tmp = namelist[index];
}
else
{
tmp = "";
}
return ( tmp );
}
set
{
if( index >= 0 && index <= size-1 )
{
namelist[index] = value;
}
}
}
public int this[string name]
{
get
{
int index = 0;
while(index < size)
{
if (namelist[index] == name)
{
return index;
}
index++;
}
return index;
}
}
static void Main(string[] args)
{
IndexedNames names = new IndexedNames();
names[0] = "Zara";
names[1] = "Riz";
names[2] = "Nuha";
names[3] = "Asif";
names[4] = "Davinder";
names[5] = "Sunil";
names[6] = "Rubic";
// 使用带有 int 参数的第一个索引器
for (int i = 0; i < IndexedNames.size; i++)
{
Console.WriteLine(names[i]);
}
// 使用带有 string 参数的第二个索引器
Console.WriteLine(names["Nuha"]);
Console.ReadKey();
}
}
}
编译执行上述代码,得到如下结果:
Zara
Riz
Nuha
Asif
Davinder
Sunil
Rubic
N. A.
N. A.
N. A.
2
C# 事件
事件
事件指一个用户操作,如按键、点击、移动鼠标等,也可以是系统生成的通知。当事件发生时,应用需要对其作出相应的反应,如中断。另外,事件也用于内部进程通信。
通过事件使用委托
事件生成于类的声明中,通过使用同一个类或其他类中的委托与事件处理程序关联。包含事件的类用于发布事件,称为发布器类。其他接受该事件的类称为订阅器类。事件使用的是发布-订阅(publisher-subscriber)模型。
发布器是一个定义了事件和委托的对象,此外还定义了事件和委托之间的联系。一个发布器类的对象调用这个事件,同时通知其他的对象。
订阅器是一个接受事件并提供事件处理程序的对象。在发布器类中的委托调用订阅器类中的方法(或事件处理程序)。
声明事件
在类中声明一个事件,首先需要声明该事件对应的委托类型。如:
public delegate void BoilerLogHandler(string status);
其次为使用 event 关键字来声明这个事件:
//基于上述委托定义事件
public event BoilerLogHandler BoilerEventLog;
上述代码段定义了一个名为 BoilerLogHandler 的委托以及一个名为 BoilerEventLog 的事件,该事件生成时会自动调用委托。
示例 1
using System;
namespace SimpleEvent
{
using System;
public class EventTest
{
private int value;
public delegate void NumManipulationHandler();
public event NumManipulationHandler ChangeNum;
protected virtual void OnNumChanged()
{
if (ChangeNum != null)
{
ChangeNum();
}
else
{
Console.WriteLine("Event fired!");
}
}
public EventTest(int n )
{
SetValue(n);
}
public void SetValue(int n)
{
if (value != n)
{
value = n;
OnNumChanged();
}
}
}
public class MainClass
{
public static void Main()
{
EventTest e = new EventTest(5);
e.SetValue(7);
e.SetValue(11);
Console.ReadKey();
}
}
}
编译执行上述代码,得到如下结果:
Event Fired!
Event Fired!
Event Fired!
示例 2
该示例为一个简单的应用程序,该程序用于热水锅炉系统故障排除。当维修工程师检查锅炉时,锅炉的温度、压力以及工程师所写的备注都会被自动记录到一个日志文件中。
using System;
using System.IO;
namespace BoilerEventAppl
{
// boiler 类
class Boiler
{
private int temp;
private int pressure;
public Boiler(int t, int p)
{
temp = t;
pressure = p;
}
public int getTemp()
{
return temp;
}
public int getPressure()
{
return pressure;
}
}
// 事件发布器
class DelegateBoilerEvent
{
public delegate void BoilerLogHandler(string status);
// 基于上述委托定义事件
public event BoilerLogHandler BoilerEventLog;
public void LogProcess()
{
string remarks = "O. K";
Boiler b = new Boiler(100, 12);
int t = b.getTemp();
int p = b.getPressure();
if(t > 150 || t < 80 || p < 12 || p > 15)
{
remarks = "Need Maintenance";
}
OnBoilerEventLog("Logging Info:\n");
OnBoilerEventLog("Temparature " + t + "\nPressure: " + p);
OnBoilerEventLog("\nMessage: " + remarks);
}
protected void OnBoilerEventLog(string message)
{
if (BoilerEventLog != null)
{
BoilerEventLog(message);
}
}
}
// 该类保留写入日志文件的条款
class BoilerInfoLogger
{
FileStream fs;
StreamWriter sw;
public BoilerInfoLogger(string filename)
{
fs = new FileStream(filename, FileMode.Append, FileAccess.Write);
sw = new StreamWriter(fs);
}
public void Logger(string info)
{
sw.WriteLine(info);
}
public void Close()
{
sw.Close();
fs.Close();
}
}
// 事件订阅器
public class RecordBoilerInfo
{
static void Logger(string info)
{
Console.WriteLine(info);
}//end of Logger
static void Main(string[] args)
{
BoilerInfoLogger filelog = new BoilerInfoLogger("e:\\boiler.txt");
DelegateBoilerEvent boilerEvent = new DelegateBoilerEvent();
boilerEvent.BoilerEventLog += new
DelegateBoilerEvent.BoilerLogHandler(Logger);
boilerEvent.BoilerEventLog += new
DelegateBoilerEvent.BoilerLogHandler(filelog.Logger);
boilerEvent.LogProcess();
Console.ReadLine();
filelog.Close();
}//end of main
}//end of RecordBoilerInfo
}
编译执行上述代码,得到如下结果:
Logging info:
Temperature 100
Pressure 12
Message: O. K
C# 属性
属性
属性是类、结构体和接口的命名成员。类或结构体中的成员变量或方法称为域。属性是域的扩展,且可使用相同的语法来访问。它们使用访问器让私有域的值可被读写或操作。
属性不会确定存储位置。相反,它们具有可读写或计算它们值的访问器。
例如,有一个名为 Student 的类,带有 age、name 和 code 的私有域。我们不能在类的范围以外直接访问这些域,但是我们可以拥有访问这些私有域的属性。
访问器
属性的访问器包含有助于获取(读取或计算)或设置(写入)属性的可执行语句。访问器声明可包含一个 get 访问器、一个 set 访问器,或者同时包含二者。例如:
// 为字符类型声明一个叫 Code 的属性:
public string Code
{
get
{
return code;
}
set
{
code = value;
}
}
// 为字符类型声明一个叫 Name 的属性:
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
// 为整形类型声明一个叫 Age 的属性:
public int Age
{
get
{
return age;
}
set
{
age = value;
}
}
示例
下面的程序说明了特性是如何使用的:
using System;
namespace tutorialspoint
{
class Student
{
private string code = "N.A";
private string name = "not known";
private int age = 0;
// 为字符类型声明一个叫 Code 的属性:
public string Code
{
get
{
return code;
}
set
{
code = value;
}
}
// 为字符类型声明一个叫 Name 的属性:
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
// 为整形类型声明一个叫 Age 的属性:
public int Age
{
get
{
return age;
}
set
{
age = value;
}
}
public override string ToString()
{
return "Code = " + Code +", Name = " + Name + ", Age = " + Age;
}
}
class ExampleDemo
{
public static void Main()
{
// 创建一个 Student 类的对象
Student s = new Student();
// 为 student 对象设置 code,name 和 age
s.Code = "001";
s.Name = "Zara";
s.Age = 9;
Console.WriteLine("Student Info: {0}", s);
//为 age 加 1
s.Age += 1;
Console.WriteLine("Student Info: {0}", s);
Console.ReadKey();
}
}
}
编译执行上述代码,得到如下结果:
Student Info: Code = 001, Name = Zara, Age = 9
Student Info: Code = 001, Name = Zara, Age = 10
抽象属性
抽象类可拥有抽象属性,这些属性应在派生类中被实现。下面的程序说明了这点:
using System;
namespace tutorialspoint
{
public abstract class Person
{
public abstract string Name
{
get;
set;
}
public abstract int Age
{
get;
set;
}
}
class Student : Person
{
private string code = "N.A";
private string name = "N.A";
private int age = 0;
// 为字符类型声明一个叫 Code 的属性:
public string Code
{
get
{
return code;
}
set
{
code = value;
}
}
// 为字符类型声明一个叫 Name 的属性:
public override string Name
{
get
{
return name;
}
set
{
name = value;
}
}
// 为整形类型声明一个叫 Age 的属性:
public override int Age
{
get
{
return age;
}
set
{
age = value;
}
}
public override string ToString()
{
return "Code = " + Code +", Name = " + Name + ", Age = " + Age;
}
}
class ExampleDemo
{
public static void Main()
{
// 创建一个 Student 类的对象
Student s = new Student();
// 为 student 对象设置 code,name 和 age
s.Code = "001";
s.Name = "Zara";
s.Age = 9;
Console.WriteLine("Student Info:- {0}", s);
//为age加1
s.Age += 1;
Console.WriteLine("Student Info:- {0}", s);
Console.ReadKey();
}
}
}
编译执行上述代码,得到如下结果:
Student Info: Code = 001, Name = Zara, Age = 9
Student Info: Code = 001, Name = Zara, Age = 10
github地址:
代码汇总:
using System;
using System.Collections.Generic;
using System.IO;
/*
C# 泛型 (OK)
C# 匿名方法 (OK)
C# 委托 (OK)
C# 集合 (OK)
C# 索引器 (OK)
C# 事件 (OK)
C# 属性 (OK)
C# 特性
C# 反射
C# 不安全代码
C# 多线程
*/
namespace cs_10
{
class MainClass
{
public static void Main(string[] args)
{
if(0 == 1){
// int array
BeyondGenericArray<int> intArr = new BeyondGenericArray<int>(5);
for (int i = 0; i < 6; i++){
intArr.setItem(i, i * 2);
}
for (int i = 0; i < 6; i++)
{
Console.Write(intArr.getItem(i) + " ");
}
Console.WriteLine();
// char array
BeyondGenericArray<char> charArr = new BeyondGenericArray<char>(26);
for (int i = 0; i < 26; i++){
charArr.setItem(i, (char)(i + 97));
}
for (int i = 0; i < 26; i++){
Console.Write(charArr.getItem(i) + " ");
}
}
if(1 == 2){
// 可以创建自己的泛型接口、泛型类、泛型方法、泛型事件和泛型委托
int a1, a2;
char c1, c2;
a1 = 6;
a2 = 7;
c1 = 'a';
c2 = 'z';
// show before swap
Console.WriteLine("a={0},b={1},c={2},d={3}",a1,a2,c1,c2);
Swap<int>(ref a1, ref a2);
Swap<char>(ref c1, ref c2);
Console.WriteLine("a={0},b={1},c={2},d={3}", a1, a2, c1, c2);
}
if (2 == 3) {
// 创建委托实例
NumberChangerDelegate<int> delegate1 = new NumberChangerDelegate<int>(AddNumFunc);
NumberChangerDelegate<int> delegate2 = new NumberChangerDelegate<int>(MultNumFunc);
Console.WriteLine($"initial num is : {getNum()}");
// 使用委托对象调用方法
delegate1(3);
Console.WriteLine($"after add 3 , num is {getNum()}");
delegate2(2);
Console.WriteLine($"after multiply 2 , num is {getNum()}");
}
if (3 == 4)
{
Console.WriteLine("1");
// 使用匿名方法创建委托实例 (right hand is anonymous method)
NumberChangerDelegate2 delegate3 = delegate(int x){
Console.WriteLine("3");
Console.WriteLine($"In Anonymous Method: {x}");
return x;
};
Console.WriteLine("2");
// 使用匿名方法调用委托
delegate3(3);
Console.WriteLine($"initial num is : {getNum()}");
// 普通方式 创建委托实例 (使用命名方法实例化委托)
delegate3 = new NumberChangerDelegate2(AddNumFunc);
// 使用命名方法调用委托
delegate3(3);
Console.WriteLine($"after add 3 , num is {getNum()}");
// 普通方式 创建委托实例 (使用命名方法实例化委托)
delegate3 = new NumberChangerDelegate2(MultNumFunc);
delegate3(2);
Console.WriteLine($"after multiply 2 , num is {getNum()}");
}
if (4 == 5){
// 使用命名方法实例化委托
NumberChangerDelegate2 delegate1 = new NumberChangerDelegate2(AddNumFunc);
NumberChangerDelegate2 delegate2 = new NumberChangerDelegate2(MultNumFunc);
Console.WriteLine($"initial num is : {getNum()}");
// 使用委托对象调用方法
delegate1(3);
Console.WriteLine($"after add 3 , num is {getNum()}");
delegate2(2);
Console.WriteLine($"after multiply 2 , num is {getNum()}");
}
if (5 == 6) {
// 多播,组播
// 创建委托实例
NumberChangerDelegate2 delegate4;
NumberChangerDelegate2 delegateAdd = new NumberChangerDelegate2(AddNumFunc);
NumberChangerDelegate2 delegateMult = new NumberChangerDelegate2(MultNumFunc);
delegate4 = delegateAdd;
// 委托对象可通过 "+" 运算符进行合并
// 方法add执行完后,立即执行方法mult;相当于ios代理或block;相当于js中的callback;相当于java中listener或handler
delegate4 += delegateMult;
// 调用多播
delegate4(3);
Console.WriteLine($"after 多播, num is : {getNum()}");
}
if (6 == 7) {
printStrDelegate delegate1 = new printStrDelegate(WriteToScreenFunc);
printStrDelegate delegate2 = new printStrDelegate(WriteToFileFunc);
sendStrFunc(delegate1);
sendStrFunc(delegate2);
}
if (7 == 8){
MainClass mainClass = new MainClass();
mainClass[0] = "beyond";
mainClass[1] = "mathilda";
mainClass[2] = "menma";
for (int i = 0; i < MainClass.size; i++){
Console.WriteLine(mainClass[i]);
}
}
if (8 == 9)
{
MainClass mainClass = new MainClass();
mainClass[0] = "beyond";
mainClass[1] = "mathilda";
mainClass[2] = "menma";
// 带有 int 参数的第一个索引器
for (int i = 0; i < MainClass.size; i++)
{
Console.WriteLine(mainClass[i]);
}
// 带有 string 参数的第二个索引器
Console.WriteLine(mainClass["mathilda"]);
}
if (9 == 10){
MainClass mainClass = new MainClass(67);
// 订阅事件
mainClass.changeNumEvent += new NumManipulationEventHandler(displayFunc);
mainClass.changeNumEvent += delegate () {
Console.WriteLine("anonymous methods as event handler");
};
mainClass.SetValue(5);
mainClass.SetValue(20);
}
if (10 == 11) {
Leader leader = new Leader();
SoldierA a = new SoldierA(leader);
SoldierB b = new SoldierB(leader);
leader.RaiseCup("left");
leader.RaiseCup("right");
leader.BreakCup();
}
if (11 == 12)
{
BoilerFileLogger fileLog = new BoilerFileLogger("test.txt");
BoilerEventPublisher eventPublisher = new BoilerEventPublisher();
// 事件订阅
eventPublisher.boilerLogEvent += new BoilerEventPublisher.BoilerLogEventHandler(MainClass.loggerFunc);
eventPublisher.boilerLogEvent += new BoilerEventPublisher.BoilerLogEventHandler(fileLog.loggerFunc);
// 手动触发事件
eventPublisher.logProcess();
fileLog.close();
}
if (12 == 13)
{
Student stu = new Student();
stu.Code = "No.1";
stu.Name = "Beyond";
stu.Age = 18;
Console.WriteLine("Student Info: {0}", stu);
stu.Age += 12;
Console.WriteLine("Student Info: {0}", stu);
}
if (13 == 13){
Girl mathilda = new Girl();
mathilda.Cup = "AA";
mathilda.Age = 12;
mathilda.Name = "玛蒂尔达";
Console.WriteLine("The Girl is : {0}", mathilda);
mathilda.Cup = "A";
mathilda.Age += 1;
Console.WriteLine("The Girl is : {0}", mathilda);
}
}
// other static function ==============
static void displayFunc(){
Console.WriteLine("hello world");
}
static void Swap<T>(ref T leftHandSide, ref T rightHandSide){
T temp;
temp = leftHandSide;
leftHandSide = rightHandSide;
rightHandSide = temp;
}
// Generic delegate ==============
delegate T NumberChangerDelegate<T>(T n);
static int num = 67;
public static int AddNumFunc(int otherNum){
num += otherNum;
return num;
}
public static int MultNumFunc(int otherNum){
num *= otherNum;
return num;
}
public static int getNum(){
return num;
}
// common delegate ==============
// 匿名方法通过使用 delegate 关键字创建委托实例来实现方法的声明
delegate int NumberChangerDelegate2(int n);
// other property ==============
static FileStream fileStream;
static StreamWriter streamWriter;
delegate void printStrDelegate(string s);
static void WriteToScreenFunc(string str){
Console.WriteLine($"the string is : {str}");
}
static void WriteToFileFunc(string s){
// ./bin/debug/test.txt
fileStream = new FileStream("test.txt",FileMode.Append,FileAccess.Write);
streamWriter = new StreamWriter(fileStream);
streamWriter.WriteLine(s);
streamWriter.Flush();
streamWriter.Close();
fileStream.Close();
}
// 该方法把委托作为参数,并使用它调用方法
static void sendStrFunc(printStrDelegate psDelegate){
psDelegate("Hello Beyond");
}
// other property for index ==============
private string[] nameArr = new string[size];
public static int size = 10;
// constructor
public MainClass(){
for (int i = 0; i < size; i++){
nameArr[i] = "N. A.";
}
}
// 带有 int 参数的第一个索引器
public string this[int index]{
get{
string tmpStr;
if(index >= 0 && index < size){
tmpStr = nameArr[index];
}else{
tmpStr = "";
}
return (tmpStr);
}
set{
if(index >= 0 && index < size){
// value is default inputParam
nameArr[index] = value;
}
}
}
// 带有 string 参数的第二个索引器
public int this[string girlName]{
get{
int index = 0;
while(index < size){
if(nameArr[index] == girlName){
return index;
}
index++;
}
return index;
}
}
// other property for event ==================
private int value;
// 在类中声明一个事件,首先需要声明该事件对应的委托类型
public delegate void NumManipulationEventHandler();
// 基于上述委托定义事件
public event NumManipulationEventHandler changeNumEvent;
protected virtual void OnNumChanged(){
if(changeNumEvent != null){
changeNumEvent();
}else{
Console.WriteLine("Event Fired");
}
}
// constructor override
public MainClass(int n){
SetValue(n);
}
public void SetValue(int n){
if(value != n){
value = n;
OnNumChanged();
}
}
// other static methods ==================
static void loggerFunc(string info){
Console.WriteLine(info);
}
}
// other class ==============
class BeyondGenericArray<T>{
private T[] array;
// constructor
public BeyondGenericArray(int size)
{
array = new T[size + 1];
}
public T getItem(int index){
return array[index];
}
public void setItem(int index, T item){
array[index] = item;
}
}
// other class for event and delegate==============
class Leader{
// other property for event and delegate ==================
public void RaiseCup(string handSide)
{
Console.WriteLine("首领{0}手举杯", handSide);
if (raiseCupEvent != null)
{
raiseCupEvent(handSide);
}
}
public void BreakCup()
{
Console.WriteLine("首领摔杯为号");
if (breakCupEvent != null)
{
breakCupEvent();
}
}
public delegate void RaiseCupEventHandler(string handSide);
public delegate void BreakCupEventHandler();
public event RaiseCupEventHandler raiseCupEvent;
public event BreakCupEventHandler breakCupEvent;
}
class SoldierA{
Leader leader;
// constructor
public SoldierA(Leader l){
this.leader = l;
leader.raiseCupEvent += new Leader.RaiseCupEventHandler(raiseCupEventHandlerFunction);
leader.breakCupEvent += new Leader.BreakCupEventHandler(breakCupEventHandlerFunction);
}
public void raiseCupEventHandlerFunction(string handSide){
if(handSide.Equals("left")){
Attack();
}
}
public void breakCupEventHandlerFunction(){
Attack();
}
public void Attack(){
Console.WriteLine("soldier A attack");
}
}
class SoldierB
{
Leader leader;
// constructor
public SoldierB(Leader l)
{
this.leader = l;
leader.raiseCupEvent += new Leader.RaiseCupEventHandler(raiseCupEventHandlerFunction);
leader.breakCupEvent += new Leader.BreakCupEventHandler(breakCupEventHandlerFunction);
}
public void raiseCupEventHandlerFunction(string handSide)
{
if (handSide.Equals("right"))
{
Attack();
}
}
public void breakCupEventHandlerFunction()
{
Attack();
}
public void Attack()
{
Console.WriteLine("soldier B attack");
}
}
// other property for boiler event and delegate ==================
class Boiler {
private int temp;
private int pressure;
// constructor
public Boiler(int t, int p)
{
this.temp = t;
this.pressure = p;
}
public int getTemp()
{
return this.temp;
}
public int getPressure()
{
return this.pressure;
}
}
// 事件发布器
class BoilerEventPublisher{
public delegate void BoilerLogEventHandler(string status);
// 基于上述委托定义事件
public event BoilerLogEventHandler boilerLogEvent;
public void logProcess(){
string remarks = "O.K";
Boiler b = new Boiler(100, 12);
int t = b.getTemp();
int p = b.getPressure();
if(t > 150 || t < 80 || p > 15 || p < 12){
remarks = "Need Maintenance";
}
onBoilerLogEvent($"Logging Info: \t {DateTime.Now}\n");
onBoilerLogEvent($"Temperature {t} \nPressure: {p}");
onBoilerLogEvent($"\nMessage: {remarks}");
}
protected void onBoilerLogEvent(string message){
if(boilerLogEvent != null){
boilerLogEvent(message);
}
}
}
// 写入日志文件
class BoilerFileLogger{
FileStream fs;
StreamWriter sw;
public BoilerFileLogger(string filename){
fs = new FileStream(filename, FileMode.Append, FileAccess.Write);
sw = new StreamWriter(fs);
}
public void loggerFunc(string info){
sw.WriteLine(info);
}
public void close(){
sw.Close();
fs.Close();
}
}
// other class no 属性 with getter & setter ==================
class Student {
// field : code name & age
private string code = "N.A";
private string name = "not known";
private int age = 0;
// property Code Name & Age
public string Code
{
get
{
return this.code;
}
set
{
this.code = value;
}
}
public string Name
{
get
{
return this.name;
}
set
{
this.name = value;
}
}
public int Age
{
get
{
return this.age;
}
set
{
this.age = value;
}
}
public override string ToString()
{
return "Property Code = " + Code + ", Name = " + Name + ", Age = " + Age;
}
}
// abstract class no 属性 with getter & setter ==================
abstract class Person{
// 抽象类可拥有抽象属性,这些属性应在派生类中被实现。
public abstract string Name{
get;
set;
}
public abstract int Age{
get;
set;
}
}
class Girl : Person {
// field: cup & name & age
private string cup = "N.A";
private string name = "N.A";
private int age = 0;
// property: Cup & Name & Age
// 声明一个叫 Cup 的属性(Property)
public string Cup {
get {
return this.cup;
}
set{
this.cup = value;
}
}
public override string Name {
get => this.name;
set => this.name = value;
}
public override int Age {
get => this.age;
set => this.age = value;
}
public override string ToString()
{
return "Property Cup = " + Cup + ", Name = " + Name + ", Age = " + Age;
}
}
}
未完待续,下一章节,つづく