泛型
object : 1、任何父类出现的地方,都可以用子类来代替;2、object是一切类型的父类。3、装箱(值从栈复制到堆里)拆箱(堆复制到栈里),性能问题,安全问题
2.0才出现的泛型 T 泛型方法: 声明的时候可以不指定类型,使用的时候指定类型;
泛型在编译器编译时不确定类型,占位符表达;机器码的时候类型已确定,在CLR用指定的类型把占位符替换掉了。
泛型缓存
缓存:把数据存起来,下次直接用上次的结果。
静态字段缓存,静态属性常驻内存。
Webservice wcf 不支持泛型:服务在发布的时候 参数类型需要确认好.
泛型方法 public void A<T>(T t) {}: 为了一个方法满足不同的类型的需求
泛型类 public class A<T> List<T>{} : 为了一个类满足不同类型的需求
public class AChild<T1,T2>: A<T1>,B<T2>{}
泛型接口 public interface A<T> {}: 一个接口满足不同类型的需求
泛型委托 public delegate void A<T> {}: 一个委托满足不同类型的需求
泛型约束
public void A (T t){} 没有约束,任何参数都能传递进来,不安全。
基类约束:public void A (T t) : where T:BaseModel{}:可以把T当作基类--权利;传入的参数必须是BaseModel或者其子类。
接口约束
引用类型约束 public T GetT<T>() where T:class{}
值类型约束 public T GetT<T>() where T:struct{}
无参数构造函数约束 public T GetT<T>() where T:new(){}
用泛型类型参数约束
public static void showTS<T,S>(T t,S s) where T:People where S:T{}
密封类不行,密封类没有子类
约束可以叠加 public void A (T t) : where T:BaseModel1,I1,I2,new(){}
协变、逆变 :泛型接口 泛型委托
协变:让右边可以用子类,让泛型用起来更方便
例如: IEnumerable<T> t = new List<S>(); S是T的子类
out修饰 只能作为返回值,不能作为参数
逆变:让右边可以用父类
in 修饰 只能作为参数,不能作为返回值
反射
IL:也是一种面向对象的语言,但是不太好阅读
metadata元数据:数据清单,描述了dll/exe里面的各种信息
反射Reflection:System.Reflection,是.Net Framework 提供的一个帮助类库,可以读取并使用metadata元数据
1、动态加载 一个完整dll名称 不需要后缀 从exe所在的路径进行查找
Assembly assembly = Assembly.Load(“dll名称”);
Assembly assembly = Assembly.Load(“dll文件所在的完整路径 并且包括后缀”);
Assembly assembly = Assembly.LoadFrom(“dll名称.后缀” 或者 “dll文件所在的完整路径 并且包括后缀”);
- 获取类型 assembly.GetType(“完整类型名称”)
泛型类 assembly.GetType(“完整类型名称^1”) 添加占位符
3、创建对象 object oDBHelper = Activator.CreateInstance(type); //到此步 不能直接调用对象中的方法(因为编译器不允许);类型强制转换之后才能被调用
IDBHelper oDBHelper = oDBHelper as IDBHelper; //as 关键词转换不报错,类型不对转换结果为null
动态类型 dynamic 可以直接调用(动态类型编译器不检查,运行时才检查):
dynamic oDBHelper = Activator.CreateInstance(type);
程序可配置:通过修改配置文件就可以自动切换,不需要重新改代码 编译 发布
程序可扩展:完全不修改原有代码,只是增加新的实现。Copy,修改配置文件,就可以支持新功能。
反射的动态加载和动态创建对象 以及配置文件结合
反射的优势:动态
反射的缺点:调用繁琐、避开了编译器检查、性能问题(反射耗时稍微高一丢丢,大量循环会影响性能;进行缓存优化后,把dll加载和类型获取只执行一次,反射影响就变的更小了)。
单例模式:就是一个类,能保证在整个进程中只有一个实例。
如果反射创建对象之后,知道方法名称,怎么样不做类型转换 直接调用对象中的方法?
1、普通方法
MethodInfo methodInfo = type.getMethod(“方法名”);
methodInfo.Invoke(对象oDBHelper ,方法参数);
2、重载方法(方法名一样,方法参数类型或者个数不同):
MethodInfo methodInfo = type.getMethod(“方法名”,new Type[]{ typeof(int) }); //找方法的时候将方法参数按照顺序将类型传入
methodInfo.Invoke(对象oDBHelper ,new object[]{123});
3、静态方法对象实例可以要也可以不要:
MethodInfo methodInfo = type.getMethod(“方法名”);
methodInfo.Invoke(null ,方法参数);
4、私有方法:
MethodInfo methodInfo =
type.getMethod(“方法名”,BindingFlags.Instance|BindingFlags.NonPublic);
5、泛型方法:
MethodInfo methodInfo = type.getMethod(“方法名”);
//设置泛型类型,得到全新的方法
var method = methodInfo.MakeGenericMethod(new Type[]{typeof(int)})
method .Invoke(对象oDBHelper ,方法参数);
6、泛型类 + 泛型方法
Assembly assembly = Assembly.Load(“dll名称”);
Type type = assembly.GetType(“完整类型名称^1”).MakeGenericMethod(new Type[]{typeof(int)});
Object oObject = Activator.CreateInstance(type);
MethodInfo methodInfo = type.getMethod(“方法名”).MakeGenericMethod(new Type[]{typeof(string)});
methodInfo.Invoke(oObject ,new object[]{1,”2”});
dll名称--类型名称--方法名称 目前就能调用方法
MVC就是应用的此方法,调用Action,MVC在启动时会先加载,扫描全部的dll,找到全部的Controller存起来,等请求来之后用Controller来匹配dll
MVC局限性--Action重载--反射是无法区分的--只能通过http get post 请求方式区分
AOP--反射调用方法可以在前后进行其他操作
通过反射动态 生成sql语句