Using attributes

A declarative way of associating information to code can be done via attributes. However, only a few attributes can be used on every type. Instead, they are used for specific types. Attributes on any type can be specified by using square brackets, [], on top of the type that we want to apply.

Let's take a look at the following code. Generally, we see the Serializable attribute when we want to serialize an object to the binary or XML formats. In real-world applications, when we need to transfer a large object over the wire, we serialize an object into one of the aforementioned formats and then send it. The serialize attribute on a class enables runtime to allow converting the object to binary or XML or any format required by the program:

[Serializable]
public class AttributeTest
{
//object of this class can now be serialized
}

Another common usage of attributes is in unit test projects. Observe the following code:

namespace Chapter10.Test
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
}
}
}

In the preceding code snippet, we create a new test project where two attributes are added to each class and method. By adding them in this way, we are letting the framework know that this class represents a test class and that the method is a test method.

As mentioned earlier, the use of attributes can be restricted to specific types. To achieve this, we will use attribute targets. By default, an attribute is applied to the preceding type. However, using a target, we can set whether the attribute applies to a class, method, or an assembly.

When the target is set to assembly, it means that the attribute is applied to the entire assembly. Similarly, a target can be set to a module, field, event, method, property, or type.

For example, an attribute can be set on a field to let the runtime know what type of input is accepted. Additionally, it can be set on a method to specify whether it is a normal method or a web method.

Some common attributes defined by the framework include the following:

  • Global: Attributes that are applied at the assembly or module level are generally global attributes, for example, AssemblyVersionAttribute. You might have seen this in every .NET project that is created using Visual Studio.

Let's take a look at the following example. Here, you can see the assembly.cs file created when you create any .NET project using Visual Studio. Every assembly contains the following code, which tells the runtime about the current assembly that is being executed:

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

[assembly: AssemblyTitle("Chapter10")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Chapter10")]
[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("f8a2951a-4520-4d0f-ab30-7dd609db84d5")]

[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
  • Obsolete: This attribute allows us to mark an entity or a class that should not be used. Therefore, when applied, it generates a warning message that is provided while applying the attribute. This class defines three constructors: the first without any parameters, the second with one parameter, and the third with two parameters. From a code-readability perspective, it is recommended that we use constructors with parameters as they generate warning or error messages based on usage. Additionally, setting the second parameter to true while applying an attribute will throw an error, whereas false will generate a warning. In the following code, we will see how we can use an obsolete attribute.

In the following code snippet, we defined a class named Firstclass; later, a new class was created with the name SecondClass. When we want new users accessing our library to use the second class rather than the first class, then we can use an Obsolete attribute with a message so that new users will see it and act accordingly:

[System.Obsolete(Firstclass is not used any more instead use SecondClass)]
class FirstClass
{
//Do Firstthing
}

class SecondClass
{
//Do Secondthing
}
  • Conditional: When a conditional attribute is applied, the execution of the preceding code depends on the evaluation of the attribute. In a real-project scenario, while running a program in a live environment, you don't want to log information and messages and fill up your storage. Instead, you can have a conditional attribute on your log methods, which will allow you to write when a flag in your configuration file is set to true. In this way, you can actually implement selecting logging.

In the following code, we have a LogMessage method; however, the attribute above the class will let the runtime application know that, when the LogErrorOn attribute is set to yes or true, it should execute this method:

using System; 
using System.Diagnostics;
Public class Logging
{
[Conditional(LogErrorON)]
public static void LogMessage(string message)
{
Console.WriteLine(message)
}
}
public class TestLogging
{
static void Main()
{
Trace.Msg(
"Main method executing...");
Console.WriteLine(
"This is the last statement.");
}
}


  • Caller information: The caller information attribute allows you to retrieve who is calling the method. They are CallerfilePathAttribute, CallerLineNumberAttribute, CallerMemberNameAttribute. Each one has its own purpose, as their names suggest. They allow us to get the line number, the method name, and the path of the file. 
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.206.69