4 进阶
约 1617 字大约 5 分钟
2025-04-05
协变: 和谐的变化,自然的变化
因为里氏替换原则父类可以装子类,所以子类变父类感受是和谐的 比如 string 变成 object
逆变: 逆常规的变化,不正常的变化 因为里氏替换原则父类可以装子类但是子类不能装父类,所以父类变子类感受是不和谐的 比如 object 变成 string
协变和逆变是用来修饰泛型占位符的 协变:out 逆变:in
用于在泛型中修饰泛型占位符的,只有泛型接口和泛型委托能使用
- 使用out修饰的泛型只能作为返回值
- 使用in修饰的泛型只能作为参数
namespace Test
{
delegate T TestOut<out T>();
delegate void TestIn<in T>(T t);
class Father { }
class Son : Father { }
class Program
{
static void Main()
{
// 协变:父类装子类
TestOut<Son> os = () =>
{
return new Son();
};
TestOut<Father> of = os;
Father f = of();
// 逆变:子类装父类
TestIn<Father> iF = (value) => { };
TestIn<Son> iS=iF;
iS(new Son());
}
}
}
加上out后的委托函数可以直接使用父类对象接收子类对象(协变) 加上in后的委托函数可以将子类对象传入到接收父类对象的参数中(逆变)
多线程
- 创建线程
Thread t=new Thread(任务函数)
- 启动线程 线程不启动是不会执行任务函数的
t.Start()
- 设置后台线程 默认创建的进程是前台进程,里面的任务不执行完毕无法关闭程序
t.IsBackground=true
将线程设置成后台线程后关闭进程这个线程也会被关闭
- 终止线程
t.Abort()
- 休眠线程 在哪个线程中执行休眠的就是哪个线程,单位:毫秒
Thread.Sleep();
锁
执行完lock的作用域块内的代码后会自动开锁
lock(obj){
}
预处理器指令
预处理器指令指导编译器在实际编译开始之前对信息进行预处理 预处理器指令都是以#开始 预处理器指令不是语句,所以它们不以分号;结束
- 折叠代码块
#region
#endregion
- 定义
#define
#undef
- 判断
#if
#elif
#else
#endif
- 提示
#warning
#error
特性
特性是一种允许我们向程序的程序集添加元数据的语言结构,它是用于保存程序结构信息的某种特殊类型的类 特性提供功能强大的方法以将声明信息与C#代码(类型、方法、属性等)相关联。 特性与程序实体关联后,即可在运行时使用反射查询特性信息 特性的目的是告诉编译器把程序结构的某组元数据嵌入程序集中,它可以放置在几乎所有的声明中(类、变量、函数等等申明)
特性本质是个类,我们可以利用特性类为元数据添加额外信息,比如一个类、成员变量、成员方法等等为他们添加更多的额外信息之后可以通过反射来获取这些额外信息
特性也就是装饰器,注解
自定义特性
自定义特性需要写一个类,这个类必须继承Attribute 命名一般是特性的功能+Attribute 在使用时会默认省略掉Attribute
class MyCustomAttribute : Attribute
{
public string info;
public MyCustomAttribute(string info)
{
this.info = info;
}
}
[MyCustom("info")]
class MyClass { }
使用
在使用时使用反射机制判断一个对象上是否带有某个特性 参数一:特性的类型 参数二:是否搜索继承链(属性和事件忽略此参数)
if(t.IsDefined(typeof(MyCustomAttribute),false)){
Console.WriteLine("该类型应用了MyCustomAttribute特性");
}
用法
在类、函数、变量上面一行写上表示他们具有该特性
[特性名(参数列表)]
传递给特性的参数也就是传递个声明这个特性类的构造函数
限制
为自定义特性限制使用范围
- AttributeTargets一特性能够用在哪些地方
- AllowMultiple一是否允许多个特性实例用在同一个目标上
- Inherited一特性是否能被派生类和重写成员继承
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct,AllowMultiple =true,Inherited =true)]
class MyCustomAttribute : Attribute{}
常用特性
特性 | 作用 |
---|---|
Obsolete | 提示用户该成员已经过时 |
CallerFilePath/LineNumber/MemberName | 调用者信息:哪个文件/行/函数调用的 |
Conditional | 条件编译特性,作用于函数上只有传入的符号被预处理指令#define定义过的调用被修饰的函数时,这个函数才会被执行 |
DllImport | 标记非C#语言的函数,表明该函数是在外部的dll包中定义的,调用其他语言写的dll包(如c,c++)时使用 |
迭代器
使用foreach基于范围的for循环的类都是实现了GetEnumerator,current,next,reset等函数 通常实现这个函数都是继承IEnumerable类,但不继承这个类直接实现GetEnumerator也会被foreach识别 current,next,reset函数在IEnumertor中 也就是要实现一个拥有迭代器的类就要继承IEnumerable和IEnumertor并实现其中的函数
使用yield return实现迭代器
使用yield return实现迭代器就不用实现current,next,reset函数了,只实现GetEnumerator就行
public IEnumerator GetEnumerator(){
for(int i=0;i<list.Length;i++){
yield return list[i];
}
}
yield return暂时返回保留当前的状态 使用yield return实现迭代器编译器会自动生成current,next,reset
特殊语法
var
可变类型,相当于c++中的auto 使用var声明的变量必须立即赋值,不能用作类的成员变量声明 主要作用就是偷懒
匿名类型
var v=new {name="w",age=10}
可空类型
值类型不可为null,但是设置可空类型就可以赋值为null了
int? a=null
GetValueOrDefault获取可空类型的值或默认值,int默认值为0,布尔为false... 也可以传入参数指定默认值
引用类型也可以使用可空类型
o?.ToString()
使用?.运算符判断前面的对象是否为空,如果为空后面的函数就不会被执行,如果不为空后面的函数就会执行
空合并操作符
?? 如果左边值不为空就返回左边值,否则返回右边值
int a=v??100;
模板字符串
string a=$"nihao{1+2}";
贡献者
版权所有
版权归属:PinkDopeyBug