1.指定AttributeUsage特性
特性(attribute)类本身用一个特性——System.AttributeUsage特性来标记。AttributeUsage主要用于标识自定义特性可以应用到哪些类型的程序元素上。这些信息由它的第一参数给出,改参数是必选的,其类型是枚举类型的AttributeTargets。
AttributeTargets枚举的成员如下:
All,Assembly,Class,Constructor,Delegate,Enum,Event,Field,GenericParameter,Interface,Method,Module,Parameter,Property,ReturnValue,Struct。
这个列表列出了可以应用该特性的所有程序元素。注意在把特性应用到程序元素上时,应把特性放在元素前面的方括号中。但是,在上面的列表中,Assembly和Module的值不对应任何程序元素,它们可以应用到整个程序集或模块中,而不是应用到代码中的一个元素上,在这种情况下,这个特性可以放在源代码的任何地方,但需要关键字Assembly或Module作为前缀:
[assembly:SomeAssemblyAttribute(Parameters)]
[module:SomeAssemblyAttribute(Parameters)]
在指定自定义特性的有效目标元素时,可以使用按位OR运算符把这些值组合起来。
例:[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field),AllowMultiple = false,Inherited = false)]
AttributeUsage特性还包含另外两个参数:AllowMultiple和Inherited。
AllowMultiple参数表示一个特性是否可以多次应用到同一项上,上面设置为false,标识编译器在同一个属性或字段上添加两次或以上的特性就会产生一个错误。
Inherited参数设置为true,就表示应用到类或接口上的特性也可以自动应用到所有派生的类或接口上。如果特性应用到方法或属性上,它就可以自动应用到该方法或属性等的重写版本上
参考案例如下(结合反射程序集一起使用):
第一步定义特性类(放置到指定的类库VectorClass中):
namespace WhatsNewAttributes
{
/// <summary>
/// 声明特性的标记(可用于类和方法上,且可以在该类或方法中多次使用,不能继承)
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
public class LastModifiedAttribute : Attribute //该特性类用于标记最后一次修改数据项的时间
{
/// <summary>
/// 只读修正时间
/// </summary>
private readonly DateTime _dateModified;
/// <summary>
/// 只读改变信息
/// </summary>
private readonly string _changes;
public LastModifiedAttribute(string dateModified, string changes)
{
_dateModified = DateTime.Parse(dateModified);
_changes = changes;
}
public DateTime DateModified => _dateModified;
public string Changes => _changes;
/// <summary>
/// 可选参数,用于描述问题重要性
/// </summary>
public string Issues { get; set; }
}
}
namespace WhatsNewAttributes
{
/// <summary>
/// 声明一个程序集特性:主要用于标记通过LastModifiedAttribute维护的文档;作为一个标记入口
/// </summary>
[AttributeUsage(AttributeTargets.Assembly)]
public class SupportsWhatsNewAttribute : Attribute
{
}
}
第二步使用特性类(在另一类库中定义实用类)
[assembly: SupportsWhatsNew]//这段代码添加了一行用SupportsWhatsNew特性标记的程序集;可在调用的时候验证是否在该类中使用了程序集特性
namespace VectorClass
{
/// <summary>
/// 该类主要用于实现对特性类LastModified的调用,在方法和类上声明了一些特性
/// </summary>
[LastModified("2015年6月6日", "为C#6和.NET核心更新")]
[LastModified("2010年12月14日", "实现了IEnumerable接口:向量可以作为集合处理")]
[LastModified("2010年2月10日", "实现了Iformattable接口:矢量可以接受n和ve格式说明符")]
public class Vector : IFormattable, IEnumerable<double>
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
public Vector(double x, double y, double z)
{
X = x;
Y = y;
Z = z;
}
[LastModified("2010年2月10日", "方法加入格式化")]
public string ToString(string format, IFormatProvider formatProvider)
{
if (format == null)
{
return ToString();
}
switch (format.ToUpper())
{
case "N":
return "|| " + Norm().ToString() + " ||";
case "VE":
return $"( {X:E}, {Y:E}, {Z:E} )";
case "IJK":
var sb = new StringBuilder(X.ToString(), 30);
sb.Append(" i + ");
sb.Append(Y.ToString());
sb.Append(" j + ");
sb.Append(Z.ToString());
sb.Append(" k");
return sb.ToString();
default:
return ToString();
}
}
public double Norm() => X * X + Y * Y + Z * Z;
[LastModified("2015年6月6日", "添加以实现IEnumerable<T>")]
public IEnumerator<double> GetEnumerator() => new VectorEnumerator(this);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public override string ToString() => $"({X} , {Y}, {Z}";
public double this[uint i]
{
get
{
switch (i)
{
case 0:
return X;
case 1:
return Y;
case 2:
return Z;
default:
throw new IndexOutOfRangeException(
"尝试检索向量元素" + i);
}
}
}
}
}
namespace VectorClass
{
/// <summary>
///该类主用于实现对特性类LastModified的调用,在方法和类上声明了一些特性
/// </summary>
[LastModified("2015年6月6日", "已更改为实现通用接口IEnumerator")]
[LastModified("2010年2月14日", "作为集合支持Vertor的一部分创建的类")]
public class VectorEnumerator : IEnumerator<double>
{
readonly Vector _theVector; // Vector object that this enumerato refers to
int _location; // which element of _theVector the enumerator is currently referring to
public VectorEnumerator(Vector theVector)
{
_theVector = theVector;
_location = -1;
}
public bool MoveNext()
{
++_location;
return (_location <= 2);
}
public object Current => Current;
double IEnumerator<double>.Current
{
get
{
if (_location < 0 || _location > 2)
throw new InvalidOperationException(
"枚举器要么在第一个元素之前,要么在向量的最后一个元素之后");
return _theVector[(uint)_location];
}
}
public void Reset()
{
_location = -1;
}
public void Dispose()
{
// nothing to cleanup
}
}
}
调用方式:
可创建一个控制台运行项目进行调用测试或其他方式,下面我使用的是控制台输出
class Program
{
private static readonly StringBuilder outputText = new StringBuilder(1000);
private static DateTime backDateTo = new DateTime(2015, 2, 1);
static void Main(string[] args)
{
//加载VectorClass程序集
Assembly theAssembly = Assembly.Load(new AssemblyName("VectorClass"));
//验证它是否真的用SupportsWhatsNew特性标记
Attribute supportsAttribute = theAssembly.GetCustomAttribute(typeof(SupportsWhatsNewAttribute));
string name = theAssembly.FullName;
AddToOutput($"Assembly:{name}");
if (supportsAttribute == null)
{
AddToOutput("程序集不支持WhatsNew Attributes");
return;
}
else
{
AddToOutput("类型:");
}
//获取包括在该程序集中定义的所有类型的集合
IEnumerable<Type> types = theAssembly.ExportedTypes;
foreach (Type definedType in types)
{
//给outputText字段添加相关的文本,包括LastModifiedAttribute类的任何实例的详细信息
DisplayTypeInfo(definedType);
}
Console.WriteLine($"What\'s New 从{backDateTo}");
Console.WriteLine(outputText.ToString());
Console.ReadLine();
}
private static void DisplayTypeInfo(Type type)
{
//检查传递的引用是否是一个类
if (!type.GetTypeInfo().IsClass)
{
return;
}
AddToOutput($"\n类:{type.Name}");
IEnumerable<LastModifiedAttribute> attributes = type.GetTypeInfo().GetCustomAttributes().OfType<LastModifiedAttribute>();
if (attributes.Count() == 0)
{
AddToOutput("这个类没有被改变过");
}
else
{
foreach (LastModifiedAttribute attribute in attributes)
{
WirteAttributeInfo(attribute);
}
}
AddToOutput("这个类被改变过");
foreach (MethodInfo method in type.GetTypeInfo().DeclaredMethods.OfType<MethodInfo>())
{
IEnumerable<LastModifiedAttribute> attributesToMethods = method.GetCustomAttributes().OfType<LastModifiedAttribute>();
if (attributesToMethods.Count() > 0)
{
AddToOutput($"类型:{method.ReturnType};方法名:{method.Name}()");
foreach (Attribute attribute in attributesToMethods)
{
WirteAttributeInfo(attribute);
}
}
}
}
private static void AddToOutput(string v)
{
outputText.Append("\n" + v);
}
private static void WirteAttributeInfo(Attribute attribute)
{
LastModifiedAttribute lastModifiedAttribute = attribute as LastModifiedAttribute;
if (lastModifiedAttribute == null)
{
return;
}
DateTime modifiedDate = lastModifiedAttribute.DateModified;
//修改日期 < 选择的日期
if (modifiedDate < backDateTo)
{
return;
}
AddToOutput($"修正:{modifiedDate:D}:{lastModifiedAttribute.Changes}");
if (lastModifiedAttribute.Issues != null)
{
AddToOutput($"未解决问题:{lastModifiedAttribute.Issues}");
}
}
}
}
输出结果如下: