C#知识点——学习笔记
我是按照菜鸟驿站的顺序学习的,这里记录一些我作为一个刚接触C#的小白的理解。更多的详细的解释以及代码示例可以参考以下链接
(https://www.runoob.com/csharp/csharp-attribute.html)
特性和反射
将这两个放在一起写是因为反射可以读出我们添加的特性
特性:
特性(Attribute)是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签。您可以通过使用特性向程序添加声明性信息。一个声明性标签是通过放置在它所应用的元素前面的方括号([ ])来描述的。
元数据:
元数据(Metadata),又称中介数据、中继数据,为描述数据的数据(data about data),主要是描述数据属性(property)的信息,用来支持如指示存储位置、历史数据、资源查找、文件记录等功能。
元数据我的理解就是一些描述信息,也可以理解为是字符串、文本。
特性实质上就是一个类,这个类中定义了一些私有变量以及公有变量记录了我们的元数据。并定义一些方法获得和返回我们的元数据。
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
我们可以通过自己定义一个属性来明白它的作用。我们在定义属性,也就是在定义一个类之前,去声明上面这样的代码。AttributeTargets的描述是为了声明,这个特性可以附加在什么对象上面。具体含义附上链接:
(https://blog.csdn.net/weixin_33690367/article/details/93898041)
定义一个特性一定要有构造函数,这样我们可以在使用特性的时候将声明的一些元数据传给我们的特性,再传递给我们附加的对象上面。
// 一个自定义特性 BugFix 被赋给类及其成员
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
public class DeBugInfo : System.Attribute
{
private int bugNo;
private string developer;
private string lastReview;
public string message;
public DeBugInfo(int bg, string dev, string d)
{
this.bugNo = bg;
this.developer = dev;
this.lastReview = d;
}
public int BugNo
{
get
{
return bugNo;
}
}
public string Developer
{
get
{
return developer;
}
}
public string LastReview
{
get
{
return lastReview;
}
}
public string Message
{
get
{
return message;
}
set
{
message = value;
}
}
}
我们新定义的特性,也就是这个类,需要继承System.Attribute
使用特性的时候,如果需要为类声明,就加在类声明的前面,如果需要为成员函数声明,就加在函数定义的前面。
public class Myclass
{
[Conditional("DEBUG")]
public static void Message(string msg)
{
Console.WriteLine(msg);
}
}
上面代码就是为Message添加了一个对象,并且声明是只有在DEBUG模式下函数有效。
反射:
反射指程序可以访问、检测和修改它本身状态或行为的一种能力。
程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。
您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。
using System;
using System.Reflection;
namespace BugFixApplication
{
// 一个自定义特性 BugFix 被赋给类及其成员
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
public class DeBugInfo : System.Attribute
{
private int bugNo;
private string developer;
private string lastReview;
public string message;
public DeBugInfo(int bg, string dev, string d)
{
this.bugNo = bg;
this.developer = dev;
this.lastReview = d;
}
public int BugNo
{
get
{
return bugNo;
}
}
public string Developer
{
get
{
return developer;
}
}
public string LastReview
{
get
{
return lastReview;
}
}
public string Message
{
get
{
return message;
}
set
{
message = value;
}
}
}
[DeBugInfo(45, "Zara Ali", "12/8/2012",
Message = "Return type mismatch")]
[DeBugInfo(49, "Nuha Ali", "10/10/2012",
Message = "Unused variable")]
class Rectangle
{
// 成员变量
protected double length;
protected double width;
public Rectangle(double l, double w)
{
length = l;
width = w;
}
[DeBugInfo(55, "Zara Ali", "19/10/2012",
Message = "Return type mismatch")]
public double GetArea()
{
return length * width;
}
[DeBugInfo(56, "Zara Ali", "19/10/2012")]
public void Display()
{
Console.WriteLine("Length: {0}", length);
Console.WriteLine("Width: {0}", width);
Console.WriteLine("Area: {0}", GetArea());
}
}//end class Rectangle
class ExecuteRectangle
{
static void Main(string[] args)
{
Rectangle r = new Rectangle(4.5, 7.5);
r.Display();
Type type = typeof(Rectangle);
// 遍历 Rectangle 类的特性
foreach (Object attributes in type.GetCustomAttributes(false))
{
DeBugInfo dbi = (DeBugInfo)attributes;
if (null != dbi)
{
Console.WriteLine("Bug no: {0}", dbi.BugNo);
Console.WriteLine("Developer: {0}", dbi.Developer);
Console.WriteLine("Last Reviewed: {0}",
dbi.LastReview);
Console.WriteLine("Remarks: {0}", dbi.Message);
}
}
// 遍历方法特性
foreach (MethodInfo m in type.GetMethods())
{
foreach (Attribute a in m.GetCustomAttributes(true))
{
DeBugInfo dbi = (DeBugInfo)a;
if (null != dbi)
{
Console.WriteLine("Bug no: {0}, for Method: {1}",
dbi.BugNo, m.Name);
Console.WriteLine("Developer: {0}", dbi.Developer);
Console.WriteLine("Last Reviewed: {0}",
dbi.LastReview);
Console.WriteLine("Remarks: {0}", dbi.Message);
}
}
}
Console.ReadLine();
}
}
}
我们来分析上面的代码,可以看到我们定义了一个DebugInfo特性和一个Rentangle类,如果不考虑反射的话,我们是看不到任何与特性相关的内容。
反射的声明System.Reflection.MemberInfo info = typeof(MyClass);
我们通过typeof获得想要获取对象的特征信息,当我们不通过反射来获取特性的时候,这些消息像是被隐藏掉了一样。我们通过GetCustomAttributes方法将获取的属性绑定到Attibute的变量上,便可以得知“隐藏”起来的内容。
总结
所以我们为什么需要特性以及反射呢?
首先,我们有需要一些元数据声明的需求,并且这些声明有时候会用到,有时候并不需要。例如上述代码,元数据保存的作者,日期等信息很多时候不会被需要到,但有的时候,需要根据特性里面的一些变量对于函数做出不同的操作,比如[Conditional("DEBUG")]
那么反射的作用就是帮助我们锁定我们想要获取特性的对象,并取出相应的信息。
那么想,如果我不通过特性,把想做的事情都写在函数里呢?首先我们有很多已经定义好的特性模板,可以直接添加上。并且我们如果想让某一个元数据附加在类上,另一个附加在函数上,还有变量上,绑定的十分麻烦,并且不易于我们查看和使用。
以上是我对特性和反射的理解。