Most of the time you will be using a standard attribute provided by the .NET framework. Standard attributes are 'picked up' and interpreted by the C# compiler to have special meanings. Unlike custom attributes, you do not need to write a special attribute class to use them. They have either been coded “ and are part of the .NET BCLs “ or are implicitly understood by the C# compiler. I will examine two of the three standard attributes reserved by C# first “ Obsolete and Conditional . The third reserved attribute, AttributeUsage , is a bit special and is discussed in Chapter 28. 27.2.1 The Obsolete attributeThis attribute is used to mark types and type members that should no longer be used. [7] You can use this attribute on classes, structures, and members such as delegates, methods , constructors, properties, fields, and events. Here is an example of how the Obsolete attribute can be used.
1: using System; 2: 3: public class ClassB{ 4: 5: [Obsolete()] 6: private int MyInteger; 7: 8: public static void Main (){ 9: ClassA a = new ClassA(); 10: } 11: 12: public int PerformOp (int i){ 13: MyInteger = i; 14: return i*2; 15: } 16: } 17: 18: [Obsolete("There are problems with this class")] 19: public class ClassA{ 20: // codes 21: } Compiler warning: c:\expt>csc test.cs test.cs(9,5): warning CS0618: 'ClassA' is obsolete: 'There are problems with this class' test.cs(9,20): warning CS0618: 'ClassA' is obsolete: 'There are problems with this class' test.cs(13,5): warning CS0612: 'ClassB.MyInteger' is obsolete In the example above, I have tagged ClassA (on line 18) and field MyInteger (on line 5) as obsolete using the [Obsolete] attribute specification. During compilation, warning messages inform you about that. If you are using csc.exe , note that the compilation warning messages appear only when there are attempts to use the entities tagged as Obsolete . (If you comment out line 9, the obsolete warning for ClassA will not appear because ClassA is never used). Another observation is that you can pass into the Obsolete attribute specification either nothing (line 5) or a string (line 18). If nothing is passed in, a default warning is shown. If a string is passed in, the string is shown as the warning message. In fact, the Obsolete attribute can take in an additional boolean parameter: [Obsolete ("My message", true)] The boolean parameter is the error parameter. If true is passed in, a compilation error is created instead of a warning. Remember the attribute class needed to write our own custom attributes I mentioned briefly ? Just keep in mind that the possible parameters an attribute specification can take in is determined by the different overloaded constructors written in this attribute class. For Obsolete , you can imagine that the ObsoleteAttribute class has three overloaded constructors “ one which takes in nothing, one which takes in a string, and one which takes in a string and a boolean parameter. I will revisit this idea in writing our custom attribute classes. 27.2.2 The Conditional attributeThis section assumes that you understand preprocessor directives and conditional compilation (see Chapter 24) but skipping this section will not affect your understanding of the remaining material in this chapter. The Conditional attribute can be used instead of the #if , #elif , and #else preprocessor directives for conditional compilation. By tagging a method as Conditional , that method may or may not be included in the resultant IL codes, depending on whether a particular symbol has been defined. Study the example below: 1: #define DEBUG 2: using System; 3: using System.Diagnostics; 4: 5: public class TestClass{ 6: 7: public static void Main (){ 8: PerformOp(); 9: Console.WriteLine("Finishing Main"); 10: } 11: 12: [Conditional("DEBUG")] 13: public static void PerformOp (){ 14: Console.WriteLine("Running PerformOp"); 15: } 16: } Output: c:\expt>test Running PerformOp Finishing Main Line 3 has to be included so that the Conditional attribute class can be found by the compiler. Notice that the DEBUG symbol is #define d on line 1. The PerformOp method (lines 13 “ 15) has been tagged with the Conditional attribute specification, which takes in a string as parameter (line 12). In this case, the DEBUG symbol is passed into the Conditional attribute specification. What line 12 effectively says, is if the DEBUG symbol is defined, compile the PerformOp method normally. Otherwise, do not compile the PerformOp method “ or any other statements in the code that invoke the PerformOp method (such as line 8) “ into IL codes. The output shows that PerformOp() has been invoked, as expected, in Main() . Let's comment off line 1, so that the DEBUG symbol is not defined. 1: // #define DEBUG 2: using System; 3: using System.Diagnostics; 4: 5: public class TestClass{ 6: 7: public static void Main (){ 8: PerformOp(); 9: Console.WriteLine("Finishing Main"); 10: } 11: 12: [Conditional("DEBUG")] 13: public static void PerformOp (){ 14: Console.WriteLine("Running PerformOp"); 15: } 16: } Output: c:\expt>test Finishing Main In this case, the whole PerformOp method (lines 13 “ 15) is being ignored, together with any invocations of PerformOp (line 8) during compilation. The shaded lines are the lines which eventually make it into IL codes, and the new output reflects exactly that. Conditional can only take in a single string, and can only be applied to methods. You cannot use it to tag classes, fields, and other class entities. There are some other special rules concerning its use:
Not following these rules will simply result in a compilation error. 27.2.3 Other standard attributesTable 27.1 gives a brief description of other standard attributes in the .NET framework. There are many others not listed. Table 27.1. Standard attributes
In the code fragment below, the [Serializable] attribute is applied to the class MyClass . This tells the compiler to make the class serializable: [Serializable] public class MyClass { // codes here } I shall discuss how to write custom attributes in the next chapter. |