The C# Attribute

原创 2004年06月30日 15:58:00

There are numerous ways designers have coupled information with classes, fields, members of a class. Category of a property, transaction context for a method, persistence mapping, keywords to extend programming languages, using external files, etcetera, have been suggested by Anders Hejlsberg, Microsoft. Each of these have advantages over each other and along with them, various drawbacks that need to be hurdled to come up with a usable solution.

While working for a previous employer, a major Dutch company that no longer exists, we created a programming environment for application programmers, where we wanted to hide the database details (including but not limited to which database was used) behind object-oriented programming. The idea was simple: Application programmers (people using our environment) could create Java applications quickly without having to worry about database specific details.  They would also maintain metadata about classes in a XML-file per Java class, using a user interface.  We developed an XML based development repository to store this metadata (XML files). The programming environment (implemented using Visual Studio shell extensions) and the development repository was written in C++. The environment generated table creation/alteration code and stored procedures for a multitude of databases.  Based on the metadata for each Java class, the byte code (generated by Java complier) was 'patched' to insert calls to the specific stored procedures.  The clear advantage was code written once in Java could be made to perform differently without recompiling, simply by editing the associated XML.  The disadvantage was XML and Java needed to be kept in sync.  To overcome this hurdle, we had to develop tools to maintain synchronicities.  We could have used C#'s attributes instead of worring about synchronization.

C# introduced attributes, which allow you to embed information right into the C# source code. Attributes are placed in square brackets, e.g. [MTAThread], above an Attribute Target (e.g. class, field, method, etcetera).  C# Attributes can be used to mark fields, methods, classes etcetera with markings that another program can interpret.  For example you can send instructions to compiler to emit a warning message 
    [Obsolete("This delegate should be avoided.  Support may be discontinued in next version")]
or generate an error for obsoleted methods. 
    [Obsolete("This method has been obsoleted as of version", true)]
See help on the [ObsoleteAttribute] in the C# language specification.

Specify attributes between square brackets ([ and ]) in C++ and between angle brackets (< and >) in Visual Basic.


public static int Main(string[] args) {
Indicates that the default threading model for an application is single-threaded apartment.  Here the Attribute Target is Method.  It also implies that there is a class (implemented by the environment in this case) by the name of STAThreadAttribute, with a parameter-less constructor STAThreadAttribute()
[MTAThread] [MTAThread] is short for [MTAThreadAttribute], in C#. In other words "Attribute" suffix is optional.  If you are working in a mixed environment, you should use the full name MTAThreadAttribute versus the shortcut MTAThread.
[Obsolete] [Obsolete] can be used to mark an Attribute Target as obsolete.  The compiler picks this attribute and emits a message or generates an error
public class PrecisionAttribute {
    public void PrecisionAttribute(int length, int precision) {
Indicates that the user defined attribute PrecisionAttribute can be applied to fields only. It also indicates that there is a constructor of name AttributeUsageAttribute(AttributeTargets t) in a class AttributeUsageAttribute. Again this class AttributeUsageAttribute is implemented by the .Net environment.
[PrecisionAttribute(7, 3)] or
[Precision(7, 3)]
Indicates that there is a constructor of name PrecisionAttribute(int, int) in a class PrecisionAttribute, possibly implemented by you.
[In] or [InAttribute] Both mean the same thing.
[InAttribute, Out, CustomMarshaller(true, UnmanagedType.U4))]
TraderIdentifier trId
[In] [Out]
[CustomMarshaller(true, UnmanagedType.U4)]
TraderIdentifier trId;
Attributes may be combined using the comma separator or listed separately within square brackets.
public static extern IntPtr GetWindow(IntPtr hWnd, int uCmd);
Instructs the compiler to insert code to allow dynamic access to dll.

Sample Code

Here is a sample that shows how to create a custom attribute and code to use the same program.  This simply allows you to store the formatting with the declaration.  For example consider these two examples:

        public int socialSecurityNumber;
        [FormattingAttribute("(###) ###-####")]
        public long phoneNumber;

Class hierarchy

Here is the class hierarchy for the sample code. 

Class AttributeSample houses the main function. FormattingAttribute is the code for the attribute and contains a private class Core with core functionality.  Classes Person, USCitizen, USEmployee implement the ISupportsFormatting interface and the hierarchical relationship between them is shown in the class hierarchy below. ISupportsFormatting requires methods string Fields() and string Field (string field) to be implemented by the class implementing the interface.



Here is the code sample in it's entirety. Enjoy ! 

Let me know what you think or if you can find a sharp use of C# attributes.

Dickey B. Singh,
Director Software Development

 System;  System.Reflection;  System.Collections;  System.Text;  AttributeSample {   AttributeSample { [STAThreadAttribute]    Main(string[] args) {  { USEmployee usemployee =  USEmployee("John Doe", 30, 987654321, 8005551212, 36000);  Console.WriteLine(usemployee.Field("socialSecurityNumber")); Console.WriteLine("");  Console.WriteLine(usemployee.Fields()); 

Console.WriteLine("Paused... Press any key.");
 }  (Exception x){ Console.WriteLine(x.Message); Console.WriteLine(x.StackTrace);  -1; }  1; } }   Person: ISupportsFormatting {   name; [FormattingAttribute("### years")]   age; [FormattingAttribute("0#/0#/####")]   someImportantDate = 09241972; [Formatting("0.###E+000")]    someUselessLongValue;  Person( name,  age) { someUselessLongValue = -1234567890123456789; = name; this.age = age; }   Fields() { FormattingAttribute.FormattedMembersToString(this); }   Field(string field) {  FormattingAttribute.FormattedMembers(this, field); } }   USCitizen : Person, ISupportsFormatting { [FormattingAttribute("###-##-####")]   socialSecurityNumber; [FormattingAttribute("(###) ###-####")]   phoneNumber;  USCitizen( name,  age,  socialSecurityNumber,  phoneNumber) : (name, age) { this.phoneNumber = phoneNumber; this.socialSecurityNumber = socialSecurityNumber; } }   USEmployee : USCitizen, ISupportsFormatting{ [FormattingAttribute("00#")]   [] intArray = {1, 17, 9, 141, 12}; [FormattingAttribute("000.0#")]   [] longArray = {1, 17, 9, 1410008974574645367, 12}; [FormattingAttribute("$#,#")]   yearlySalary;  USEmployee(string name, int age, int ssn, long ph, int sal) : base(name, age, ssn, ph) { yearlySalary = sal; } }  interface ISupportsFormatting {  Fields();  Field(string field); } [AttributeUsageAttribute(AttributeTargets.Field)]   FormattingAttribute : System.Attribute {   format;  FormattingAttribute(string format) { .format = format; }  static string FormattedMembers(object o, string caseSensitiveFieldName) {  (caseSensitiveFieldName == null) throw new NullReferenceException();  Core.FormattedMembers(o, caseSensitiveFieldName)[0]; }  static string[] FormattedMembers(object o) {  Core.FormattedMembers(o, null); }  static string FormattedMembersToString(object o) {  sReturn = null; ( s  FormattingAttribute.FormattedMembers(o)) sReturn += s + delimiter;  sReturn; }    delimiter = "/n";    Delimiter {  { delimiter = ( ==  || .Length == 0)?"/n":; }  {  delimiter; } }   Core {   [] FormattedMembers( o,  caseSensitiveFieldName) {  (o == )  new NullReferenceException();  BindingFlags bindingflags = BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance;  MemberInfo[] memberInfos = o.GetType().GetMembers(bindingflags); ArrayList a =  ArrayList(memberInfos.GetLength(0));  (MemberInfo mi  memberInfos) {   (caseSensitiveFieldName !=  && caseSensitiveFieldName != mi.Name) ;   (mi.MemberType != MemberTypes.Field) ;   field = Field(o, mi.Name);   format = Formatting(mi);  a.Add(FieldToLine(field, mi.DeclaringType.ToString(), mi.Name, format)); }  strs = Array.CreateInstance((), a.Count); a.CopyTo(strs); a.Clear();  (string[])strs; } 
    FieldToLine( field,  declaringClass,  name,  format) {  StringBuilder sb =  StringBuilder("("+declaringClass + ") ");  (field == ) { sb.Append(name + " = null");  sb.ToString(); } sb.Append(field.GetType() + " <" + format + "> " + name + " = ");  (field.GetType().ToString().EndsWith("[]")) { System.Array array = field as System.Array;  (array == null) sb.Append ("null");  {  len = array.Length;  (len>0) sb.Append("{"); ( i=0; i<len; i++) { sb.Append(FormatObject(array.GetValue(i), format)); sb.Append((i==len-1)?"}":", "); } } }  { sb.Append(FormatObject(field, format)); }  sb.ToString(); }    FormatObject(object o, string format) { if (typeof(int) == o.GetType())  Convert.ToInt32(o).ToString(format); if (typeof(long) == o.GetType())  Convert.ToInt64(o).ToString(format);  o.ToString(); }    Field( o,  s) {  {  o.GetType().InvokeMember(s, BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetField, , o,   [] {}); }  (Exception x) { Console.WriteLine("Error writing object" + o + " " + s); Console.WriteLine(x.Message); Console.WriteLine(x.StackTrace); }  null; }    Formatting(MemberInfo mi) {  FormattingAttribute a = (FormattingAttribute)Attribute.GetCustomAttribute(mi, typeof(FormattingAttribute));   (a != null)  a.format;  string.Empty; } } } }

c# Attribute原理及使用

  • zhou8jie
  • zhou8jie
  • 2016年11月03日 11:11
  • 961


  • xiaouncle
  • xiaouncle
  • 2017年04月17日 22:45
  • 2644


  • xiaouncle
  • xiaouncle
  • 2017年04月18日 16:04
  • 1841


自定义Attribute类:VersionAttribute[AttributeUsage(AttributeTargets.Class)] public class VersionAttribute...
  • u014571132
  • u014571132
  • 2016年09月20日 15:14
  • 386


Attribute 类被称为特性.是一种可由用户自由定义的修饰符(Modifier),可以用来修饰各种需要被修饰的目标。可以修饰类,接口,属性,方法等.它不同于注释,注释在程序被编译的时候会被编译器所...
  • han_yankun2009
  • han_yankun2009
  • 2014年06月16日 23:34
  • 3411


                          区别C#中的两个属性(Property和Attribute)        在C#中有两个属性,分别为Property和Attribute,两个的中...
  • tjvictor
  • tjvictor
  • 2007年01月25日 11:27
  • 8072


这篇文章主要讲一下C#里面Attribute的使用方法 比如你把玩家的血量、攻击、防御等属性写到枚举里面。然后界面可能有很多地方要根据这个枚举获取属性的描述文本。 比如你做网络框架的时候,一个协议号对...
  • wangch2012
  • wangch2012
  • 2016年02月13日 10:55
  • 1342

C# 中自定义Attribute值的获取与优化

C#自定义Attribute值的获取是开发中会经常用到的,一般我们的做法也就是用反射进行获取的,代码也不是很复杂。 1、首先有如下自定义的Attribute [AttributeUsage(A...
  • hegx2001
  • hegx2001
  • 2015年12月18日 15:46
  • 7427


  • just0kk
  • just0kk
  • 2016年08月10日 04:30
  • 2087


假设我们有这么一个标记来说明操作的权限: /// /// 声明权限的标记 /// [AttributeUsage(AttributeTargets.Method)] ...
  • lee576
  • lee576
  • 2014年07月15日 10:17
  • 2367
您举报文章:The C# Attribute