1.delegate 自然是要和 目的方法有相同的参数。
delegate要初始化:
public delegate void CatchEventHandler;
CatchEventHandler delegate1 = new CatchEventHandler( CatchMethod );
或者
CatchEventHandler delegate1 = CatchMethod ;
绑定多个方法时,按顺序执行。
CatchEventHandler delegate1 = CatchMethod ; 第一次赋值,都是用“+” 而不是“+=”
delegate1+ = CatchMethod 2;
所以不能
CatchEventHandler delegate1 = new CatchEventHandler( );
delegate1+ = CatchMethod ; X
delegate1+ = CatchMethod 2;
delegate作为方法的参数时,如同 string,int 类型一样,在具体调用时,把具有相同参数签名的方法名作为参数直接传递就行。get(1,“s”, CatchMethod )+_+
具有相同参数签名的方法,用delegate代替,可以少写switch判断逻辑。(当然是分情况啦)
delegate是类,继承于基类的delegate,可以在定义class的任意位置定义delegate。
2. 不同类间的通信,就可能用到event。为了保留observer的引用。当subject的内容变更时,需要这些引用来执行observer的方法。
如果不用event持有observer的引用在subject里,那subject里的event的声明换做delegate其实也可以。
但是delegate的话就需要做访问器了(set,get),而event不需要可以直接使用。
而且初始化方式不同。
event: ClassPer.event1 += new Handler(method);
delegate: ClassPer.delegate1 = new Handler(method);
event其实也是特殊的delegate。event 的事件类型就是 delegate,如:
①public delegate void CatchEventHandler();
则 ②public event CatchEventHandler CatchEvent;
①是delegate的定义。②event只是delegate的引用,不是方法没有参数。跟直接的delegate引用声明CatchEventHandler CatchEvent 类似。
3.event其实就是在发生其他类或对象关注的事情时,该类可以通过event通知其他类。
4.event要有效用,必须先绑定(注册)。就是把委托用 += 赋值与event。
5.注册的delegate要先实例化。就是把同delegate具有相同参数签名的 方法名,放在需要实例化的delegate括号里。
CatchEvent += new CatchEventHandler(CatchMethod)。
对象里运用了event的话,这里的方法 CatchMethod,一般都会是其他类或对象的 方法。
6.event可以注册多个delegate(同delegate的多播委托区别?)
7.event要传递参数的话( object sender, EventArgs args),那delegate也 同样咯,同时目的方法也 要相同的参数。
EventArgs 是基类,运用时,一般都是从它继承出来的子类,可以存储数据信息。
8..Net Framework的编码规范:
委托类型的名称都应该以EventHandler结束。
委托的原型定义:有一个void返回值,并接受两个输入参数:一个Object 类型,一个 EventArgs类型(或继承自EventArgs)。
事件的命名为 委托去掉 EventHandler之后剩余的部分。
继承自EventArgs的类型应该以EventArgs结尾。
委托声明原型中的Object类型的参数代表了Subject,也就是监视对象,在本例中是 Heater(热水器)。回调函数(比如Alarm的MakeAlert)可以通过它访问触发事件的对象(Heater)。
EventArgs 对象包含了Observer所感兴趣的数据。
9.可以参考的文章 http://www.cnblogs.com/cntour365/archive/2008/08/29/1279757.html
二.泛型
1.泛型可以说,就是类型已经参数化。泛型类的类型参数,可以用于类成员,field or property。 class
2.泛型类和接口的继承:
①泛型类继承中,父类的类型参数已被实例化,这时子类不一定必须是泛型类;
②父类的类型参数没有被实例化,但来源于子类,也就是说父类和子类都是泛型类,并且二者有相同的类型参数;
总之:父类不拥有泛型了(被实例化),子类可以拥有泛型。父类拥有泛型,则子类肯定有泛型。
3.泛型委托,泛型方法,就是 在委托或方法声明时包含类型参数,()。同时支持在方法或委托的参数里运用类型参数。(T,t)
public delegate void CatchEventHandler(T, t);
public void Catch(T, t);
泛型不可以运用在除方法以外的其他类或接口成员里,但其他成员可以使用同样作为成员的泛型的类型参数。 对照1
4.泛型方法的声明,调用,重载,覆盖(重写)
using System;
using System.Collections.Generic;
using System.Text;
namespace GenericTest
{
class GenericClass
{
//申明一个泛型方法
public T getvalue(T t)
{
return t;
}
//调用泛型方法
//注意:在调用泛型方法时,对泛型方法的类型参数实例化
public int useMethod()
{
return this.getvalue(10);
}
//重载getvalue方法
public int getvalue(int i)
{
return i;
}
}
//下面演示覆盖
//要注意的是,泛型方法被覆盖时,约束被默认继承,不需要重新指定约束关系
abstract class Parent
{
public abstract K TEST(K k, V v) where K : V;
}
class Child : Parent
{
public override T TEST(T t, S s)
{
return t;
}
}
}
5.泛型的约束关系,C#中的泛型只支持显示的约束
T:结构 类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型。
T:类 类型参数必须是引用类型,包括任何类、接口、委托或数组类型。
T:new() 类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。
T: 类型参数必须是指定的基类或派生自指定的基类。
T: 类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。
T:U 为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。这称为裸类型约束。
class B { public void F2() {} }
class C
where S: A // S继承自A
where T: B // T继承自B
{
// 可以在类型为S的变量上调用F1,
// 可以在类型为T的变量上调用F2
}
interface IComparable { int CompareTo(T v);}
interface IKeyProvider { T GetKey(); }
class Dictionary
where K: IComparable
where V: IPrintable, IKeyProvider
{
// 可以在类型为K的变量上调用CompareTo,
// 可以在类型为V的变量上调用Print和GetKey
}
class B { public B(int i) { } }
class C
where T : new()
{
//可以在其中使用T t=new T();
}
C c=new C (); //可以,A有无参构造器。 此处编译器会检查A是否具有无参构造函数。 其中A的初始化是用System.Activator.CreateInstance();实现的,反射。
C c=new C(); //错误,B没有无参构造器
public class B { }
class C
where T : struct
{
// T在这里面是一个值类型
}
C c=new C (); //可以,A是一个值类型
C c=new C(); //错误,B是一个引用类型
可以参考的文章 http://blog.csdn.net/fengsky491/archive/2008/04/07/2256414.aspx
http://www.cnblogs.com/ottox/archive/2009/03/02/1401307.html
6. 泛型委托 Predicate /Func /Action
Predicate : 定义一组条件,在指定对象中查找是否有符合条件的结果。 用于 Array 和 List;
public delegate bool Predicate < T > (T obj);
T: 要比较的对象的类型。
obj: 要按照由此委托表示的方法中定义的条件进行比较的对象。
返回值:如果 obj 符合由此委托表示的方法中定义的条件,则为 true;否则为 false。
Func<TResult>:
封装一个不具有参数但却返回 TResult 参数指定的类型值的方法。
Func(T1, TResult): Func(T1, T2, TResult), Func(T1, T2, T3, TResult), Func(T1, T2, T3, T4 TResult)
封装一个具有一个参数并返回 TResult 参数指定的类型值的方法,没有T2就是封装一个具有参数并....。
Action, Action, Action, Action, Action封装一个方法,该方法指定数量的参数(如()无参数,(T1)一个参数,以此类推)并且不返回值。这个和Func有相似处,但无返回值而已。
Lambda表达式里,用了return ,则 return 语句需要用{ }括起来。 x => x + 1; < === > x => { return x + 1; }可以参考的文章 http://www.cnblogs.com/dlonghow/archive/2009/03/25/1421413.html
三.特性Attribute / 属性 Property
1.Attribute 本身就是一个类, 是在编译的时候被实例化的,而不是像通常的类那样在运行时候才实例化。必须写在一对方括号里。
2.自定义的Attribute必须直接或者间接继承System.Attribute。所有自定义的特性名称都应该有个Attribute后缀。
如果类型名不含后缀,在引用属性类时,则可能只认含了后缀的,可以用 @ 标识符处理。
3.Attribute用作编译器指令则不受数量限制。
Conditional:起条件编译的作用,只有满足条件,才允许编译器对它的代码进行编译。一般在程序调试的时候使用。
DllImport:用来标记非.NET的函数,表明该方法在一个外部的DLL中定义。
Obsolete:这个属性用来标记当前的方法已经被废弃,不再使用了。
4.[AttriubteUsage(参数设置)],还有三个属性 AllowMultiple, Inherited, ValidOn
AttriubteUsage只能用于 System.Attribute的派生特性类,且该新特性类的 AllowMultiple 默认 为false, Inherited 默认 为true 。
using System; ======> using System;
class X: Attribute {...} [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]
class X: Attribute {...}5.自定义属性类的默认参数,一般都是 定位参数,在属性类的构造函数参数序列里定义。可选的参数也就是 命名参数,在构造函数里赋默认值,在属性类的filed 和 accesstor里定义(set方法)。
没有set方法会报错: Named attribute argument can''t be a read only property
属性AttriubteUsage中,ValidOn是定位参数,AllowMultiple, Inherited是命名参数。
6. 对于编译器来说, 属性目标说明符显示的指明了该属性希望被用于assembly 还是别的。
[assembly: Help("this a do-nothing assembly")]
可选项 * assembly, * module, * type (运用于类的时候可省略),* method, * property, * event, * field, * param, * return
7.在获取属性的时候,t.GetCustomAttributes()
程序集用
Assembly t = Assembly.LoadFrom(assemblyName);
类,方法,域用
Type t = typeof(Anyclass); 与 Type.GetType()的区别是,typeof参数为类名,GetType参数为带namespace的类全名字符串。
8.属性定义后用给自己?? 搞不明白 为啥, 编译时候顺序呢
基础可查看 http://360doc.com/content/081125/07/81764_1995927.html
高级 http://zzk.cnblogs.com/s?w=blog%3Adudu%20Attribute
四.反射 Reflection
1.采用反射技术可以简化工厂的实现。
采用反射技术可以极大地简化对象的生成,对以下设计模式的实现也有很大影响。
3.Process p = Process.GetCurrentProcess();
assemblyName = p.ProcessName + ".exe";
Assembly a = Assembly.LoadFrom(assemblyName);
Type[] mytypes = a.GetTypes();
Type ht = typeof(HelloWorld);
Object bj = Activator.CreateInstance(ht);
Object bjName = Activator.CreateInstance(ht,s);
MethodInfo [] mif = ht.GetMethods ();
MethodInfo msayhello = ht.GetMethod("SayHello");
msayhello.Invoke(obj,null);
4. 关于程序集的反射
反射appDomain 的程序集
foreach (Assembly assem in Appdomain.currentDomain.GetAssemblies())
{
运用System.Reflection.Assembly返回一个程序集
• Load(); Load 将引起CLR把策略应用到程序集上,先后在全局程序集缓冲区,应用程序基目录和私有路径下面查找该程序集,如果找不到该程序集系统抛出异常。
• LoadFrom();传递一个程序集文件的路径名(包括扩展名),CLR会载入您指定的这个程序集,传递的这个参数不能包含任何关于版本号的信息,区域性,和公钥信息,如果在指定路径找不到程序集抛出异常。
• LoadWithPartialName(); 已经废弃。
※Appdomain的Load()方法与Assembly 的静态Load()方法不同。
AppDomain的load 方法是一种实例方法,返回的是一个对程序集的引用,Assembly的静态Load 方法将程序集按值封装发回给发出调用的AppDomain。
5.关于类型的反射
几种获取type对象的方法:
• Type t = typeof(Anyclass); 与 Type.GetType()的区别是,typeof参数为类名,GetType参数为带namespace的类全名字符串。
• Type.GetType( parameter),System.type 参数为字符串类型,该字符串必须指定类型的完整名称(包括其命名空间)
• System.type 提供了两个实例方法:GetNestedType,GetNestedTypes
• Syetem.Reflection.Assembly 类型提供的实例方法是:GetType,GetTypes,GetExporedTypes
• System.Reflection.Moudle 提供了这些实例方法:GetType,GetTypes,FindTypes
6.关于成员的反射
通过type对象的GetMembers 方法取得一个类型的成员。
• 使用的是不带参数的GetMembers,它只返回该类型的公共定义的静态变量和实例成员
• 使用带参数的GetMembers通过参数设置来返回指定的类型成员
BindingFlags bf = BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public;
foreach (MemberInfo mi int t.getmembers(bf))
{
writeline(mi.membertype);
}
7.通过反射创建类型的实例
• System.Activator 的CreateInstance方法。该方法返回新对象的引用。具体使用方法参见msnd
• System.Activator 的createInstanceFrom 与上一个方法类似,不过需要指定类型及其程序集
• System.Appdomain 的方法:createInstance,CreateInstanceAndUnwrap,CreateInstranceFrom和CreateInstraceFromAndUnwrap
• System.type的InvokeMember实例方法:这个方法返回一个与传入参数相符的构造函数,并构造该类型。
• System.reflection.constructinfo 的Invoke实例方法
8.反射获取接口,只能获取一层,取父接口需要额外调用。继承关系都是如此?
9.反射的性能:
使用反射来调用类型或者触发方法,或者访问一个字段或者属性时clr 需 要做更多的工作:校验参数,检查权限等等,所以速度是非常慢的。 所以尽量不要使用反射进行编程,对于打算编写一个动态构造类型(晚绑定)的应用程序,可以采取以下的几种方式进行代替:
• 通过类的继承关系。让该类型从一个编译时可知的基础类型派生出来,在运行时生成该类 型的一个实例,将对其的引用放到其基础类型的一个变量中,然后调用该基础类型的虚方法。
• 通过接口实现。在运行时,构建该类型的一个实例,将对其的引用放到其接口类型的一个变量中,然后调用该接口定义的虚方法。
• 通过委托实现。让该类型实现一个方法,其名称和原型都与一个在编译时就已知的委托相符。在运行时先构造该类型的实例,然后在用该方法的对象及名称构造 出该委托的实例,接着通过委托调用你想要的方法。这个方法相对与前面两个方法所作的工作要多一些,效率更低一些 。
- Type.GetType属于Reflection的一部分,Reflection可以用于动态解析类型。也就是说,即使编译开发期间没有建立对 Assembly的引用,Type.GetType一样可以用于取得类型信息(相反,typeof是静态解析类型的,所以要求reference)。 如果你理解Namespace和Assembly的关系的话,就会明白单从类型的名称(包括Namespace部分)是不可能找到类型定义的,还必须知道 定义类型的Assembly的名称和位置。所以在调用Type.GetType的时候必须要附带指明Assembly的信息。
- 但我想不通了 为什么他们的实例GetType就可以呢??? Object.GetType的工作方式和上面的不同。因为你已经得到了对象实例(object),也就意味着在这之前你已经通过某种方式把定义对象的Assembly加载捣内存里了,不需要额外的信息来确定定义类型的Assembly。
可以参考 http://www.cnblogs.com/yinhu435/archive/2009/09/29/1576524.html
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/12913851/viewspace-617708/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/12913851/viewspace-617708/