元数据与反射
程序是用来处理数据的,文本和特征都是数据,而我们的程序本身(类的定义和BCL中的类)这些也是数据。(BCL:Basic Class Lib基础类库)
有关程序及其类型的数据被称为元数据(metadata),他们保存在程序的程序集中。
程序在运行时,可以查看其它程序集或其本身的元数据。一个运行的程序查看本身的元数据或者其他程序集的元数据的行为叫做反射,
class Class
{
private int a;
private int b;
public int c;
public string d;
/*自动属性是C# 5.0(含)之后,微软新增的语法糖,全称为 Auto-Implemented Properties。如果属性的set和get访问器中没有任何逻辑,就可以使用自动实现的属性。不需要声明私有化字段。编译器会自动创建它。使用自动实现的属性,就不能直接访问字段,因为不知道编译器生成的名称。使用自动实现的属性,就不能再属性中验证属性的有效性。自动实现的属性可以使用属性初始化器来初始化。
C#自动属性可以使我们节约一部分时间,即它给我们简化了敲击代码时间。也就是避免了和原来一样,我们手工声明一个私有成员属性变量和编写get和set逻辑。*/
public string Name { get; set; }//自动属性
public string Name2 { get; set; }
public void Test1()
{ }
public void Test2()
{ }
}
static void Main(string[] args)
{
//获取Type对象方法一
//Type t = typeof(Class);
//获取Type对象方法二 两种方法获取到的Type是一样的
Class myclass = new Class();
Type t = myclass.GetType();
Console.WriteLine(t.Name);//类名
Console.WriteLine(t.Namespace);//命名空间
Console.WriteLine(t.Assembly);//程序集
FieldInfo[] fis = t.GetFields();//只能获取到公共字段
foreach (FieldInfo fi in fis)
{
Console.WriteLine(fi.Name);
}
PropertyInfo[] pis = t.GetProperties();//属性
foreach (PropertyInfo pi in pis)
{
Console.WriteLine(pi.Name);
}
MethodInfo[] mis = t.GetMethods();//方法
foreach (MethodInfo mi in mis)
{
Console.WriteLine(mi.Name);
}
Console.Read();
}
运行结果:
Class
反射
反射, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
c
d
Name
Name2
get_Name
set_Name
get_Name2
set_Name2
Test1
Test2
Equals
GetHashCode
GetType
ToString
特征
特征是一种允许我们向程序运行的运行集增加元数据的语言结构。它是用于保存程序结构信息的某种特殊类型的类。
Obsolete 特征
在程序代码的更新迭代中,有些方法或类想被新的方法或类逐步替代掉,在逐步更新替换的过程中就可以使用Obsolete 属性来对旧方法或类进行标记。
Obsolete 属性将某个程序实体标记为一个建议不再使用的实体。每次使用被标记为已过时的实体时,随后将生成警告或错误,这取决于属性是如何配置的。
[Obsolete("这个方法弃用了,请使用最新的NewTest方法",false)]//特征:弃用、过时
static void Test()
{
Console.WriteLine("Test");
}
static void NewTest()
{
Console.WriteLine("NewTest");
}
static void Main(string[] args)
{
Test();
Console.Read();
}
Obsolete原型:public ObsoleteAttribute(string message, bool error);
Obsolete attribute可以不含参数;可以含一个参数,用以产生一个编译警告信息;也可以含两个参数,第一个参数用以产生编译警告/错误时的提示信息,第二个参数用以指定处理方式(true:产生编译错误;false:产生编译警告)
Conditional特征
当程序中的方法或属性不想再使用时,如果把它删掉就需要把引用的地方一个一个全部删掉不然就会编译错误,这时我们就可以在方法或属性上面加一个[Conditional(“Name”)] ,当定义一个名字为Name的宏,程序能被正常调用,当为定义一个名字为Name的宏时,程序会自动跳过所有的调用。
[Conditional("IsShowMessage")]
static void ShowMessage(string str)
{
Console.WriteLine(str);
}
static void Main(string[] args)
{
ShowMessage("Start of Main");
Console.WriteLine("Doing work in Main");
ShowMessage("End of Main");
Console.Read();
}
没有宏定义的情况:
程序运行结果
Doing work in Main
有宏定义的情况
程序运行结果
Start of Main
Doing work in Main
End of Main
重新定义一个类,Program类文件中的宏定义保持不变,
可见#if #endif内的代码是否生效,取决于当前文件是否定义该宏,别的文件下的宏无法被识别到,但是Conditional特征在别的文件也可以正常响应。
Conditional特征与#if的区别:
用Conditional属性的方式,方法是否生效是取决于调用方,而用#if方式,方法是否生效是取决于方法定义所在的程序集。
调用者信息特征
#region 调用者信息特征
static void ShowMessage(string Message, [CallerLineNumber] int LineNumber = 0, [CallerFilePath] string FilePath = "",[CallerMemberName] string MemberName = "")
{
Console.WriteLine(Message);
Console.WriteLine(LineNumber);//调用方法在源文件中的行号
Console.WriteLine(FilePath);//调用方法的文件的完整路径
Console.WriteLine(MemberName);//调用方法的方法名
}
static void Main(string[] args)
{
ShowMessage("Hello");
Console.Read();
}
#endregion
程序运行结果
DebuggerStepThrough特征
当我们在进行单步调试代码的时候,常常希望调试器不要进入某些方法。我们只想执行该方法,然后继续调试下一行。DebuggerStepThrough特性会告诉编译器在执行目标代码时不要进入该方法调试。有些方法规模很小并且毫无疑问是正确的,在调试的过程中反复单步调试是非常没有必要的。但是,要小心使用该特性,不要排除掉可能出现bug的代码。
该特性是用在方法前面的,在想要跳过的方法前面加上[DebuggerStepThrough] 即可。
#region DebuggerStepThrough特征
[DebuggerStepThrough]
static void ShowMessage(string Message)
{
Console.WriteLine(Message);
}
static void Main(string[] args)
{
ShowMessage("Hello");
Console.Read();
}
#endregion
自定义特征
特征类的定义:
1.类名必须以Attribute结尾
2.类必须继承于Attribute类
3.类必须加sealed修饰符
4.类必须要有构造函数,对字段进行赋值
//自定义特征类注意点:
//1.类名必须以Attribute结尾
//2.类必须继承于Attribute类
//3.类必须加sealed修饰符
//4.类必须要有构造函数,对字段进行赋值
[AttributeUsage(AttributeTargets.Class)]//表明该特征类作用于类
sealed class InformationAttribute : Attribute
{
public string developer;
public string version;
public string description;
public InformationAttribute(string _developer, string _version, string _description)
{
this.developer = _developer;
this.version = _version;
this.description = _description;
}
}
自定义类的使用:
[Information("菜鸟","V1.0","这是一个测试类")]//使用时类名不需要写Attribute
class Program
{
#region 自定义特征
static void Main(string[] args)
{
Type t = typeof(Program);
bool result = t.IsDefined(typeof(InformationAttribute),false);//判断特征是否应用于该成员
Console.WriteLine(result);
object[] Attributes = t.GetCustomAttributes(false);//返回此成员所以自定义特征
Console.WriteLine(Attributes[0].ToString());
Console.Read();
}
#endregion
代码运行结果
True
特征.InformationAttribute