疑难杂症----特性(Attribute)
//自定义了一个Attribute
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
class IStudentAttribute : Attribute
{
public string Name { get; set; }
public int Age { get; set; }
}
//下面是调用
[IStudent(Name = "abc", Age = 20)]
public void F()
{
//请问,Name 和 Age的值能取到吗?我没看到有什么用啊?
}
下面是一个网友的最佳答案
假设你的F()方法是定义在下面这个类里面:
public class MyClass
{
[IStudent(Name = "abc", Age = 20)]
public void F()
{
}
}
那么可以这么去取值:
Type type = typeof(MyClass);
MethodInfo methodInfo = type.GetMethod("F");
if (methodInfo.IsDefined(typeof(IStudentAttribute), false))
{
object[] attributes = methodInfo.GetCustomAttributes(typeof(IStudentAttribute), false);
IStudentAttribute studentAttr = (IStudentAttribute)attributes[0];
Console.WriteLine(studentAttr.Name + studentAttr.Age);
}
实际上,Attribute可以有很多用处,比如说,你可以在某个方法上做标记看有没有权限调用,或者在某个属性上标记,看要如何校验。例如(实在习惯用var关键字了,下面的代码都用var了,还有Linq):
假设我们有这么一个标记来说明操作的权限:
/// <summary>
/// 声明权限的标记
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class PermissonAttribute : Attribute
{
public string Role { get; set; }
public PermissonAttribute(string role)
{
this.Role = role;
}
public PermissonAttribute()
{
}
}
有一个操作类应用了该标记:
/// <summary>
/// 文件操作类
/// </summary>
public class FileOperations
{
/// <summary>
/// 任何人都可以调用Read
/// </summary>
[Permisson("Anyone")]
public void Read()
{
}
/// <summary>
/// 只有文件所有者才能Write
/// </summary>
[Permisson("Owner")]
public void Write()
{
}
}
然后我们写一个工具类来检查操作权限
/// <summary>
/// 调用操作的工具类
/// </summary>
public static class OperationInvoker
{
public static void Invoke(object target, string role, string operationName, object[] parameters)
{
var targetType = target.GetType();
var methodInfo = targetType.GetMethod(operationName);
if (methodInfo.IsDefined(typeof(PermissonAttribute), false))
{
// 读取出所有权限相关的标记
var permissons = methodInfo
.GetCustomAttributes(typeof(PermissonAttribute), false)
.OfType<PermissonAttribute>();
// 如果其中有满足的权限
if (permissons.Any(p => p.Role == role))
{
methodInfo.Invoke(target, parameters);
}
else
{
throw new Exception(string.Format("角色{0}没有访问操作{1}的权限!", role, operationName));
}
}
}
}
最后,在使用的时候:
var role = "Anyone";
var opertion = new FileOperations();
// 可以正常调用Read
OperationInvoker.Invoke(operation, "Read", null);
// 但是不能调用Write
OperationInvoker.Invoke(operation, "Write", null);
经典案例:
using System;
using System.Reflection; //应用反射技术获得特性信息
namespace Anytao.net
{
//定制特性也可以应用在其他定制特性上,
//应用AttributeUsage,来控制如何应用新定义的特性
[AttributeUsageAttribute(AttributeTargets.All, //可应用任何元素
AllowMultiple = true, //允许应用多次
Inherited = false)] //不继承到派生类
//特性也是一个类,
//必须继承自System.Attribute类,
//命名规范为:"类名"+Attribute。
public class MyselfAttribute : System.Attribute
{
//定义字段
private string _name;
private int _age;
private string _memo;
//必须定义其构造函数,如果不定义有编译器提供无参默认构造函数
public MyselfAttribute()
{
}
public MyselfAttribute(string name, int age)
{
_name = name;
_age = age;
}
//定义属性
//显然特性和属性不是一回事儿
public string Name
{
get { return _name == null ? string.Empty : _name; }
}
public int Age
{
get { return _age; }
}
public string Memo
{
get { return _memo; }
set { _memo = value; }
}
//定义方法
public void ShowName()
{
Console.WriteLine("Hello, {0}", _name == null ? "world." : _name);
}
}
//应用自定义特性
//可以以Myself或者MyselfAttribute作为特性名
//可以给属性Memo赋值
[Myself("Emma", 25, Memo = "Emma is my good girl.")]
public class Mytest
{
public void SayHello()
{
Console.WriteLine("Hello, my.net world.");
}
}
public class Myrun
{
public static void Main(string[] args)
{
//如何以反射确定特性信息
Type tp = typeof(Mytest);
MemberInfo info = tp;
MyselfAttribute myAttribute =
(MyselfAttribute)Attribute.GetCustomAttribute(info, typeof(MyselfAttribute));
if (myAttribute != null)
{
//嘿嘿,在运行时查看注释内容,是不是很爽
Console.WriteLine("Name: {0}", myAttribute.Name);
Console.WriteLine("Age: {0}", myAttribute.Age);
Console.WriteLine("Memo of {0} is {1}", myAttribute.Name, myAttribute.Memo);
myAttribute.ShowName();
}
//多点反射
object obj = Activator.CreateInstance(typeof(Mytest));
MethodInfo mi = tp.GetMethod("SayHello");
mi.Invoke(obj, null);
Console.ReadLine();
}
}
}
2. 下面是一个新浪网友的理解
Attribute. 对一个类型class的描述, 就像public等访问修饰符,或者方法method,属性property等类似。意义在于添加在指定类型的描述,从而通过定制来使用该attribute类型里面的成员(属性或者方法)。.net通过反射来获取注册到指定类型或者成员的所有attribute,并按照framework里制定好的规则去使用或者执行该attribute类实例。可被继承.
• using System;
• using System.Reflection;
•
• namespace CustomAttrCS {
• // An enumeration of animals. Start at 1 (0 = uninitialized).
• public enum Animal {
• // Pets.
• Dog = 1,
• Cat,
• Bird,
• }
•
• // A custom attribute to allow a target to have a pet.
• public class AnimalTypeAttribute : Attribute {
• // The constructor is called when the attribute is set.
• public AnimalTypeAttribute(Animal pet) {
• thePet = pet;
• }
•
• // Keep a variable internally ...
• protected Animal thePet;
•
• // .. and show a copy to the outside world.
• public Animal Pet {
• get { return thePet; }
• set { thePet = Pet; }
• }
• }
•
• // A test class where each method has its own pet.
• class AnimalTypeTestClass {
• [AnimalType(Animal.Dog)]
• public void DogMethod() {}
•
• [AnimalType(Animal.Cat)]
• public void CatMethod() {}
•
• [AnimalType(Animal.Bird)]
• public void BirdMethod() {}
• }
•
• class DemoClass {
• static void Main(string[] args) {
• AnimalTypeTestClass testClass = new AnimalTypeTestClass();
• Type type = testClass.GetType();
• // Iterate through all the methods of the class.
• foreach(MethodInfo mInfo in type.GetMethods()) {
• // Iterate through all the Attributes for each method.
• foreach (Attribute attr in
• Attribute.GetCustomAttributes(mInfo)) {
• // Check for the AnimalType attribute.
• if (attr.GetType() == typeof(AnimalTypeAttribute))
• Console.WriteLine(
• "Method {0} has a pet {1} attribute.",
• mInfo.Name, ((AnimalTypeAttribute)attr).Pet);
• }
•
• }
• }
• }
• }
•
•