一、::运算符和全局名称命名空间
先看一段代码
using MyNamespace = MyRootNamespace.MyNamespace1
namespace MyRootNamespace
{
namespace MyNamespace
{
public class Animal{}
}
namespace MyNamespace1
{
public class Animal{}
}
}
请问执行MyNamespace.Animal 是执行的哪一个?
答案是MyRootNamespace.MyNamespace.Animal 而不是
MyRootNamespace.MyNamespace1.Animal
也就是说别名没有生效,只不过是被隐藏了,这样的情况如果想继续使用别名(强制使用别名)就要
MyNamespace::Animal 这样会迫使编译器使用using语句定义的别名。
:: 运算符可以跟global关键字一起使用,它实际上是顶级根命名空间的别名。
global::System.Collections.Generic.List<int>
二、定制异常
关于tay…catch…finally 都很熟悉了,这里说一下自定义异常
System命名空间中有两个基本的异常类: ApplicationException 和 SystemException , 它们派生自Exception。 前者是想留给开发人员用于派生自己的异常类。 后者是.net Framework 预定义的异常的基类。 如果我们自己定制异常的话,建议直接继承Exception就可以了。
三、定义事件
关于事件的使用,以及它的几个兄弟的用法,我的这篇博客有详细介绍,可以看下
C#知识点讲解之C#delegate、event、Action、EventHandler的使用和区别
四、特性
4.1】什么是特性?
一种为使用所创建类型的代码提供额外信息的方法,就是特性。
4.2】特性有什么用?
特性让我们可以为代码段标记一些信息,而这样的信息又可以从外部读取,并通过各种方式来一ing想我们所定义的类型的使用方式。也称为对代码进行“装饰”。
别废话,看一个经常会看到的代码
[SerializeField] //在任意类型之上中括号括起来的就是特性
private string _CustomVersion;
4.3】我们自己实现一个特性吧
先上苦涩的干货:
通过System.Attribute类进行派生,创建自己的特性
派生后对派生类添加一个特性来实现(AttributeUsageAttribute),这个特性带有一个类型为AttributeTargets的构造函数参数值,通过|运算符组合,还有一个bool类型的属性AllowMultiple,是否可以多次应用特性。
废话不多说,我们来定义一个可以应用到类或属性中(一次)的特性
[AttributeUsage(AttributeTargets.class | AttibuteTargets.Methed,
AllowMultiple = false)]
class DoInterestingThingsAttribute : Attribute
{
public int HowManyTimes{get; private set;}
public string DoSomething{get; set;}
public DoInterestingThingsAttribute(int howManyTimes)
{
HowManyTimes = howManyTimes;
}
}
//使用 -- 多个特性用逗号隔开
[DoInterestingThings(1000, DoSomething = "Achieve")] //如果引入了特性所在的命名空间,类名后面的Attribute可以省略
public class DoSomeClass
{
}
4.4】读取特性
有一个好玩的点,我们可以通过反射技术在运行时,根据不同的特性采取不同的操作。
Type.GetCustomAttributes() // 具体使用自查, 返回一组object