首先特性不是装逼用的。C#中特性可以理解为Python的装饰器,他是在不改变原函数的情况下,给与一些新的功能。比如说在序列化中,我们需要给需要序列化的类添加特性[Serialize],这个相当于告诉计算机,我标记为serialize的类才可以去做序列化。
其次,特性会用到映射,在后期自定义的时候,会用到很多映射方面的知识。
创建
using System;
namespace AttributePractice
{
//特性其实就是一个类,他继承自Attribute
public class CustomAttribute : Attribute
{
public CustomAttribute()
{
}
public CustomAttribute(int num)
{
}
public CustomAttribute(int num, string str)
{
}
}
//如果一个类继承自一个特性,这个类也可以作为特性
public class CustomChildAttribute : CustomAttribute
{
}
}
使用
namespace AttributePractice
{
[CustomAttribute()]
[Custom]
[Custom()]
[Custom(1)]
[Custom(1,"string")]
public class Source
{
public int id { get; set; }
public enum CustomEnum
{
enumValue1 = 0,
enumValue2 = 1,
enumValue3 = 2
}
}
}
特性就是类,所以特性也可以继承,构造无参或者有参构造函数。在使用的时候只需要按照函数调用的方式将参数传入就可以。特性创建时的格式为XXXAttribute并且在使用的时候可以省略Attribute。比如说上面声明的CustomAttribute在使用的时候直接使用的是[Custom]。
同一个地方同一个特性不可以多次使用,如果想使用需要给自定义特性添加一个AttributeUsage特性。
AttributeUsage
using System;
namespace AttributePractice
{
[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
//特性其实就是一个类,他继承自Attribute
public class CustomAttribute : Attribute
{
public CustomAttribute()
{
}
public CustomAttribute(int num)
{
}
public CustomAttribute(int num, string str)
{
}
}
//如果一个类继承自一个特性,这个类也可以作为特性
public class CustomChildAttribute : CustomAttribute
{
}
}
AttributeUsage是一个预定义特性类,AttributeUsage类就是描述了一个定制特性如何被使用。
特性的实例
1.返回参数
using System;
using System.Reflection;
namespace AttributePractice
{
public class CustomAttribute : Attribute
{
public string _remark = string.Empty;
public CustomAttribute(string mark)
{
this._remark = mark;
}
public string Remark()
{
return this._remark;
}
}
public static class GetAttributeValue
{
public static string GetAttribute(this Enum e)
{
Type type = e.GetType();
FieldInfo field = type.GetField(e.ToString());
CustomAttribute attribute = (CustomAttribute)field.GetCustomAttribute(typeof(CustomAttribute));
return attribute.Remark();
}
}
}
1.创建一个名为Attribute的自定义特性,可以接受一个string类型的参数,在特性中我们预留一个返回值为string的方法Remark,这个方法可以将特性的字符串参数返回。
2.GetAttributeValue是一个静态类(因为我们要做一个扩展方法,扩展方法需要在一个非泛型的静态类中定义)
3.GetAttributeValue中用到很多映射知识,GetType可以理解为获得类名,然后在一级一级向下找,直到找到特性所标记位置。
4.找到后可以通过强制转化后调用Remark方法,获得特性标记的参数。
Custom特性的使用
namespace AttributePractice
{
public class Source
{
public int id { get; set; }
public enum CustomEnum
{
[Custom("测试1")]
enumValue1 = 0,
[Custom("测试2")]
enumValue2 = 1,
[Custom("测试3")]
enumValue3 = 2
}
}
}
using System;
namespace AttributePractice
{
internal class Program
{
private static void Main(string[] args)
{
string attributeValue = Source.CustomEnum.enumValue1.GetAttribute();
Console.WriteLine(attributeValue);
Console.ReadKey();
}
}
}
===============================================================================
输出结果:
测试1
2.校验
namespace AttributePractice
{
public class Source
{
[Custom(5, 2)]
public int value1 { get; set; }
[Custom(5, 2)]
public int value2 { get; set; }
[Custom(5, 2)]
public int value3 { get; set; }
[Custom(5, 2)]
public int value4 { get; set; }
[Custom(5, 2)]
public int value5 { get; set; }
}
}
using System;
namespace AttributePractice
{
public class CustomAttribute : Attribute
{
public int _max = 0;
public int _min = 0;
public CustomAttribute(int max, int min)
{
this._max = max;
this._min = min;
}
public string SubFunc(int num)
{
return (num > (_max - _min) ? true : false).ToString();
}
}
//跟上一个一样先GetType的到类名,由于Custom特性标记的是属性,所以需要再遍历一次,
//得到所以属性,然后通过判断来得到我们需要的。
public static class GetAttributeValue
{
public static void Validate<T>(this T t)
{
Type type = t.GetType();
foreach (var property in type.GetProperties())
{
var attribute = property.GetCustomAttributes(true);
foreach (var item in attribute)
{
if (item is CustomAttribute)
{
CustomAttribute custom = item as CustomAttribute;
Console.WriteLine(custom.SubFunc((int)property.GetValue(t)));
}
}
}
}
}
}
================================================================================
输出结果:
False
True
True
False
False