第二阶段WinFrom-7:文件操作补充,泛型复习,协变和逆变
1_文件操作补充
(1)判断文件是否隐藏
OpenFileDialog openFileDialog = new OpenFileDialog();
FileInfo fileInfo = new FileInfo(openFileDialog.FileName);
//如果文件隐藏,输出Hidden, Archive;文件未隐藏输出Archive
Console.WriteLine(fileInfo.Attributes);//Hidden, Archive
// & 与运算,fileInfo.Attributes输出为Hidden, Archive,则fileInfo.Attributes & FileAttributes.Hidden结果为Hidden
//fileInfo.Attributes输出为Archive,则fileInfo.Attributes & FileAttributes . Hidden 结果为0
Console.WriteLine((fileInfo.Attributes & FileAttributes.Hidden));
//HasFlag 判断 Attributes属性中是否包含某个枚举
Console.WriteLine(fileInfo.Attributes.HasFlag(FileAttributes.ReadOnly));
(2)Process类,能够对本地的进程进行操作
Start:启动或重用指定的进程;参数1可以是快捷方式,也可以时应用程序 .exe;参数2指定打开的应用的界面
//Process类 能够对本地的进程进行操作
//防抖 节流 防呆
for (int i = 0; i < 5; i++)
{
//打开文件Process.Start(@"D:\Tencent\QQNT\QQ.exe");
}
//参数2指定打开的应用的界面
Process.Start(@"C:\Program Files\Google\Chrome\Application\chrome.exe", "https://www.baidu.com");
2_泛型的概念,定义,运行原理,优势
(1) 概念:泛型是C#2.0推出的新语法,它是专门为处理多段代码在不同的数据类型上执行相同的指令的情况而设计的。
泛型让不同的数据支持相同的业务逻辑; 泛型是一个符复合数据类, 把多个类型混合在一起使用,比如方法和泛型混到一起就是泛型方法, 类和泛型混合一起就是泛型类,接口和泛型混合到一起就是泛型接口
List<T>, 如:List<int> ints = new List<int>(){10,11,12}
(2)泛型定义语法格式:
<T>或<T,K,......> 其中T,K指未知类型。 T,K,M,N 泛型定义时,是延迟声明的:即定义的时候没有指定具体的参数类型,把参数类型的声明推迟到了调用的时候才指定参数类型。
(3)运行原理: 程序最终会编译成XXX.exe,XXX.exe被点击的时候,会经过JIT的编译,生成二进制代码,才被计算机执行。使用泛型以后,VS自带的编译器又做了升级,升级之后编译时遇到泛型,会做特殊的处理:先生成占位符。再次经过JIT编译的时候,会把上面编译生成的占位符替换成具体的数据类型。
JIT:Just In Time称为即时编译器
(4)泛型优势:速度快且支持不同类型。 a.最大限度地重用代码;b.保护类型的安全以及提高性能;c.语法优美
(5)泛型应用范围:泛型方法,泛型类,泛型接口,泛型委托,泛型结构
(6)泛型约束:
泛型的目的,相同的业务逻辑,支持了不同类型。如果一味的滥用,对代码安全性不利。引入泛型约束主要控制泛型支持的类型在有限的范围内。所谓的泛型约束,实际上就是约束的类型T。使T必须遵循一定的规则。比如T必须继承自某个类,或者T必须实现某个接口等等。
五种常用的泛型约束
约束 | 说明 |
---|---|
where T:class | 引用类型约束保证T一定是引用类型的。 |
where T:struct | 值类型约束保证T一定是值类型的。 |
where T:new() | 无参数构造函数约束保证T必须有无参数构造函数,无参构造函数约束和其他约束搭配使用时,new()要放到最后。 |
where T:接口名称 | 接口约束保证T必须实现接口 |
where T:基类名 | 基类约束时,基类不能是密封类,即不能是sealed类。sealed类表示该类不能被继承,在这里用作约束就无任何意义,因为sealed类没有子类。 |
泛型约束可以同时约束多个。如:where T : People, ISports 要求T必须是People或People的子类,或同时实现ISports接口。
3_协变和逆变
(1)协变和逆变是在.NET 4.0的时候出现的,协变和逆变只能发生在泛型接口或者泛型委托中。
协变(covariant):IFoo<父类> = IFoo<子类>;out,用来修饰返回值
逆变(contravariant):IBar<子类> = IBar<父类>;in,用来修饰传入参数
(2)协变和逆变其实也是类型变化。
C#类型转换发生在单一类型中,如:小范围类型的int隐式转换成大范围类型long,大范围类型long强制转换成小范围类型int。
而泛型的协变和逆变,只发生在泛型中。泛型不是单一类型。如:List<T> List是数据类型,T也是数据类型。泛型可以认为是复合类型。
协变:类似于隐式类型转换,但有所不同。【协变控制的是返回值的类型】。如:
public interface IEnumerable<out T>
逆变:类似于强制类型转换,但有所不同。【逆变控制的是传入参数的类型】。如:public delegate bool Predicate<in T>(T obj)
协变和逆变只能发生在泛型接口或者泛型委托中,类型转换没有此限制。
(3)使用了协变以后,=左边声明的是基类,右边可以声明基类或者基类的子类。简单理解:即小转大。 如:协变 IEnumerable<Bird> birdList1 = new List<Bird>();
IEnumerable<Bird> birdList2 = new List<Sparrow>();
(4)不论协变或逆变,发生在复合类型之间,不会发生单一类型之间。 错误理解:不要理解成Sparrow继承Bird,所以new List<Sparrow>()可以赋值给IEnumerable<Bird>了。理解有偏差。 List<Sparrow>和IEnumerable<Bird>之间的关系。为什么List<Sparrow>实例可以赋值给IEnumerable<Bird> 类型。原因:IEnumerable<out T>
(5)使用了逆变之后,=左边声明是子类,右边可以声明子类或者子类的基类。简单理解:即大转小。