c#异步委托的使用

创建线程的一种简单方式是定义一个委托,并异步调用它。 委托是方法的类型安全的引用。Delegate类 还支持异步地调用方法。在后台,Delegate类会创建一个执行任务的线程。

接下来定义一个方法,使用委托异步调用(开启一个线程去执行这个方法)


static int TakesAWhile(int data,int ms){

Console.WriteLine("TakesAWhile started!");

Thread.Sleep(ms);//程序运行到这里的时候会暂停ms毫秒,然后继续运行下一语句

Console.WriteLine("TakesAWhile completed");

return ++data;

}

public delegate int TakesAWhileDelegate(int data,int ms);// 声明委托

static void Main(){

TakesAWhileDelegate d1 = TakesAWhile;

IAsyncResult ar = d1.BeginInvoke(1,3000,null,null);

while(ar.IsCompleted ==false ){

Console.Write(".");

Thread.Sleep(50);

}

int result = d1.EndInvoke(ar);

Console.WriteLine("Res:"+result);

}

C#里面的反射和特性

在C#中反射的实现是使用System.Type类实现的.

 System.Type类部分成员

成员  成员类型  描述

Name  属性  返回类型的名字

Namespace  属性  返回包含类型声明的命名空间

Assembly  属性  返回声明类型的程序集。

GetFields  方法  返回类型的字段列表

GetProperties  方法  返回类型的属性列表

GetMethods  方法  返回类型的方法列表

获取Type对象有两种方式

1,Type t = myInstance.GetType();//通过类的实例来获取Type对象

在object类有一个GetType的方法,返回Type对象,因为所有类都是从object继承的,所以我们可以在任何类型上使用GetType()来获取它的Type对象

2,Type t = typeof(ClassName);//直接通过typeof运算符和类名获取Type对象

获取里面的属性

FieldInfo[] fi = t.GetFields();

foreach(FieldInfo f in fi){

Console.WriteLine(f.Name+” “);

}

Assembly类在System.Reflection命名空间中定义,它允许访问给定程序集的元数据,它也包含了可以加载和执行程序集。

如何加载程序集?

1,Assembly assembly1 = Assembly.Load(“SomeAssembly”);根据程序集的名字加载程序集,它会在本地目录和全局程序集缓存目录查找符合名字的程序集。

2,Assembly assembly2 = Assembly.LoadFrom(@”c:\xx\xx\xx\SomeAssembly.dll”)//这里的参数是程序集的完整路径名,它不会在其他位置搜索。

1,获取程序集的全名 string name = assembly1.FullName;

2,遍历程序集中定义的类型   Type[] types = theAssembly.GetTypes();

foreach(Type definedType in types){

//

}

3,遍历程序集中定义的所有特性(稍后介绍)

Attribute[] definedAttributes = Attribute.GetCustomAttributes(someAssembly);

什么是特性?

特性(attribute)是一种允许我们向程序的程序集增加元数据的语言结构。它是用于保存程序结构信息的某种特殊类型的类。

将应用了特性的程序结构叫做目标

设计用来获取和使用元数据的程序(对象浏览器)叫做特性的消费者

.NET预定了很多特性,我们也可以声明自定义特性

应用特性

先看看如何使用特性。特性的目的是告诉编译器把程序结构的某组元数据嵌入程序集。我们可以通过把特性应用到结构来实现。

1.在结构前放置特性片段来应用特性;
2.特性片段被方括号包围,特性片段包括特性名和特性的参数列表;
3.应用了特性的结构成为特性装饰。

案例1

[Serializable]  //特性

public class MyClass{

// …

}

案例2

[MyAttribute(“Simple class”,”Version 3.57″)]  //带有参数的特性

public class MyClass{

//…

}

Obsolete特性->.NET预定义特性

一个程序可能在其生命周期中经历多次发布,而且很可能延续多年。在程序生命周期的后半部分,程序员经常需要编写类似功能的新方法替换老方法。处于多种原因,你可能不再使用哪些调用过时的旧方法的老代码。而只想用新编写的代码调用新方法。旧的方法不能删除,因为有些旧代码也使用的旧方法,那么如何提示程序员使用新代码呢?可以使用Obsolete特性将程序结构标注为过期的,并且在代码编译时,显示有用的警告信息。

class Program{

[Obsolete(“Use method SuperPrintOut”)]  //将特性应用到方法

static void PrintOut(string str){

Console.WriteLine(str);

}

[Obsolete(“Use method SuperPrintOut”,true)]//这个特性的第二个参数表示是是否应该标记为错误,而不仅仅是警告。

static void PrintOut(string str){

Console.WriteLine(str);

}

static void Main(string[] args){

PrintOut(“Start of Main”);

}

}

Conditional特性

Conditional特性允许我们包括或取消特定方法的所有调用。为方法声明应用Conditional特性并把编译符作为参数来使用。

定义方法的CIL代码本身总是会包含在程序集中,只是调用代码会被插入或忽略。

#define DoTrace

class Program{

[Conditional(“DoTrace”)]

static void TraceMessage(string str){

Console.WriteLine(str);

}

static void Main(){

TraceMessage(“Start of Main”);

Console.WriteLine(“Doing work in Main.”)

TraceMessage(“End of Main”);

}

}

调用者信息特性

调用者信息特性可以访问文件路径,代码行数,调用成员的名称等源代码信息。

1.这个三个特性名称为CallerFilePath,CallerLineNumber和CallerMemberName
2.这些特性只能用于方法中的可选参数

public static void PrintOut(string message,[CallerFilePath] string filename=””,[CallerLineNumber]int lineNumber = 0,[CallerMemberName]string callingMember=””){

Console.WriteLine(“Message:”+message);

Console.WriteLine(“Line :”+lineNumber);

Console.WriteLine(“Called from:”+callingMember);

Console.WriteLine(“Message :”+message);

}

DebuggerStepThrough特性

我们在单步调试代码的时候,常常希望调试器不要进入某些方法。我们只想执行该方法,然后继续调试下一行。DebuggerStepThrough特性告诉调试器在执行目标代码时不要进入该方法调试。有些方法小并且毫无疑问是正确的,在调试时对其反复单步调试只能徒增烦恼。要小心使用该特性,不要排除了可能出现bug的代码。

该特性位于System.Diagnostics命名空间下

该特性可用于类,结构,构造方法,方法或访问器

class Program{

int _x=1;

int X{

get{return _x;};

[DebuggerStepThrough]

set{

_x=_x*2;

_x+=value;

}

}

public int Y{get;set;}

[DebuggerStepThrough]

void IncrementFields(){

X++;

Y++;

}

static void Main(){

Program p = new Program();

p.IncrementFields();

p.X = 5;

Console.WriteLine(“P.X:”+p.X+” p.Y:”+p.Y);

Console.ReadKey();

}

}

其他预定义特性

特性                     意义

CLSCompliant  声明可公开的成员应该被编译器检查是否符合CLS。兼容的程序集可以被任何.NET兼容的语言使用

Serializable  声明结构可以被序列化

NonSerialized  声明结构不可以被序列化

DLLImport  声明是非托管代码实现的

WebMethod  声明方法应该被作为XML Web服务的一部分暴露

AttributeUsage  声明特性能应用到什么类型的程序结构。将这个特性应用到特性声明上

多个特性

我们可以为单个结构应用多个特性。有下面两种添加方式

独立的特性片段相互叠在一起

[Serializable]

[MyAttribute(“Simple class”,”Version 3.57″)]

单个特性片段,特性之间使用逗号间隔

[Serializable,MyAttribute(“Simple class”,”Version 3.57″)]

 全局特性

我们可以通过使用assembly和module目标名称来使用显式目标说明符把特性设置在程序集或模块级别。

程序集级别的特性必须放置在任何命名空间之外,并且通常放置在AssemblyInfo.cs文件中

AssemblyInfo.cs文件通常包含有关公司,产品以及版权信息的元数据。

[assembly: AssemblyTitle(“ClassLibrary1”)]

[assembly: AssemblyDescription(“”)]

[assembly: AssemblyConfiguration(“”)]

[assembly: AssemblyCompany(“”)]

[assembly: AssemblyProduct(“ClassLibrary1”)]

[assembly: AssemblyCopyright(“Copyright ©  2015”)]

[assembly: AssemblyTrademark(“”)]

[assembly: AssemblyCulture(“”)]

 自定义特性

应用特性的语法和之前见过的其他语法很不相同。你可能会觉得特性跟结构是完全不同的类型,其实不是,特性只是某个特殊结构的类。所有的特性类都派生自System.Attribute。

声明一个特性类和声明其他类一样。有下面的注意事项

声明一个派生自System.Attribute的类

给它起一个以后缀Attribute结尾的名字

(安全起见,一般我们声明一个sealed的特性类)

特性类声明如下:

public sealed class MyAttributeAttribute : System.Attribute{

特性类的公共成员可以是

字段

属性

构造函数

构造函数

特性类的构造函数的声明跟普通类一样,如果不写系统会提供一个默认的,可以进行重载

构造函数的调用

[MyAttribute(“a value”)]  调用特性类的带有一个字符串的构造函数

[MyAttribute(“Version 2.3″,”Mackel”)]  //调用特性类带有两个字符串的构造函数

构造函数的实参,必须是在编译期间能确定值的常量表达式

如果调用的是无参的构造函数,那么后面的()可以不写

构造函数中的位置参数和命名参数

public sealed class MyAttributeAttribute:System.Attribute{

public string Description;

public string Ver;

public string Reviewer;

public MyAttributeAttribute(string desc){

Description = desc;

}

}

//位置参数(按照构造函数中参数的位置)

//命名参数,按照属性的名字进行赋值

[MyAttribute(“An excellent class”,Reviewer = “Amy McArthur”,Ver=”3.12.3″)]

限定特性的使用

有一个很重要的预定义特性可以用来应用到自定义特性上,那就是AttributeUsage特性,我们可以使用它来限制特性使用在某个目标类型上。

例如,如果我们希望自定义特性MyAttribute只能应用到方法上,那么可以用如下形式使用AttributeUsate:

[AttributeUsage(AttributeTarget.Method)]

public sealed class MyAttributeAttribute : System.Attribute{

AttributeUsage有是三个重要的公共属性如下:

ValidOn  保存特性能应用到的目标类型的列表,构造函数的第一个参数就是AttributeTarget  类型的枚举值

Inherited  一个布尔值,它指示特性是否会被特性类所继承  默认为true

AllowMutiple  是否可以多个特性的实例应用到一个目标上 默认为false

事件和委托的区别

之前对事件和委托的概念一直很模糊,虽然知道怎么用,但是感觉理解还不是很透彻的.

现在总算是理解了,具体总结如下.

事件:

1.是一种特殊的委托

2.它不能在方法内定义

3.它不能在所定义的类外所调用

-事件是一种特殊的委托,或者说是受限制的委托,是委托一种特殊应用,只能施加+=,-=操作符。二者本质上是一个东西。

-event ActionHandler Tick; // 编译成创建一个私有的委托示例, 和施加在其上的add, remove方法.

-event只允许用add, remove方法来操作,这导致了它不允许在类的外部被直接触发,只能在类的内部适合的时机触发。委托可以在外部被触发,但是别这么用。

-使用中,委托常用来表达回调,事件表达外发的接口。

-委托和事件支持静态方法和成员方法, delegate(void * pthis, f_ptr), 支持静态返方法时, pthis传null.支持成员方法时, pthis传被通知的对象.

-委托对象里的三个重要字段是, pthis, f_ptr, pnext, 也就是被通知对象引用, 函数指针/地址, 委托链表的下一个委托节点.

事件(event)基于委托,为委托提供了一个发布/订阅机制,我们可以说事件是一种具有特殊签名的委托。

什么是事件?

事件(Event)是类或对象向其他类或对象通知发生的事情的一种特殊签名的委托.

事件的声明

public event 委托类型 事件名;

事件使用event关键词来声明,他的返回类值是一个委托类型。

通常事件的命名,以名字+Event 作为他的名称,在编码中尽量使用规范命名,增加代码可读性。

为了更加容易理解事件,我们还是以前面的动物的示例来说明,有三只动物,猫(名叫Tom),还有两只老鼠(Jerry和Jack),当猫叫的时候,触发事件(CatShout),然后两只老鼠开始逃跑(MouseRun)。接下来用代码来实现。(设计模式-观察者模式)

正则表达式匹配

在C#中使用正则表达会大大提高开发效率.如当你要匹配一个IPV4的地址的时候

 


string ip4 = "192.168.1.5";//你要匹配的地址
 string pattern4 = @"^((([01]?\d\d?|2[0-4]\d|25[0-5])\.){3}([01]?\d\d?|2[0-4]\d|25[0-5]))$";//匹配公式

bool  isIP=Regex.IsMatch(ip4,pattern4);//判断是否匹配成功;

Console.WriteLine(isIP);

string str1 = @"^\d*$";//正则表达式表示一个数字字符串;
 string str2="1s";//Console.ReadLine();
 bool flag=Regex.IsMatch(str2, str1);//只要有一个符合则认为是满足的

string str3 = "how to solve the problem has become to hot issue among many people";
 string pattern2=@"[^how]";
 Console.WriteLine(Regex.Replace(str3,pattern2,"*"));//把str3中出现的h,o,w字符替换为*;

lambada表达式

lambada 表达式在C#里面也是一种匿名方法的表达方式.如下


Func<int, int, int> plus1 = (a, b) =>//lambada表达式的参数是不需要声明类型的;
 {

return a+b;
 };
 Console.WriteLine(plus(5,6));//输出11;
 Func<int, int> pl = a => a + 1;//当参数只有一个的时候可以不用括号,当函数体中只有一行语句的时候也不需要大括号如果有返回值将自动返回这个值;

Console.WriteLine(pl(5));//输出6
通过Lambada表达式可以访问Lamdada表达式块的外部的变量,但是这个使用要很谨慎,因为变量很容易受到外部影响.

&nbsp;

Func<int, int, int> plus =delegate(int a,int b)//匿名方法;
 {

return a+b;

};

Console.WriteLine(pl(5,6));//输出11