How to Use Attributes in C#

Using Attributes in C#

Introduction

Usinng an attribute is a way to add special meaning to our method and cause it to act in a certain way. Before this was available, developers didn’t have a way to define their own attributes. DotNet paved the way for developers and opened new horizons to conquer. Attributes are like adding behaviours to methods, classes, properties structures, events, modules, and so forth. It means we can enforce certain constraints on those methods, classes, properties and vice-versa to behave in the way specify to them.

One more added feature is that, before DotNet, if we made a class or DLL and a newer version came along, the older version that should be removed or should not be used still exists. This causes a problem called DLL Hell. DotNet solved this problem by the concept of versioning. This means that the same DLL with the same name, containing some new methods with older methods can co-exist with a different version number.

Let us start to learn to use attributes in C# code:

Case 1

I had a method in my old DLL. Now, I have updated my DLL and added two new methods and one new method that is the upgraded version of previous DLL.

What should happen is that my previous programs that use this DLL should work properly. Or, if I intend to use the old method in the new program, it should tell me that the old method is obsolete and I should use the new method.

Before DotNet, this wasn’t possible. DotNet has removed this hurdle from the path of developers. Let us see how can we do this stuff:

Using System;
Namespace MyExample
{
   Class MyAttribute
   {
      [Obsolete()]
      public static void SaySomething(string str)
      {
         Console.WriteLine(str);
      }
      public static void Talk(string str)
      {
         Console.WriteLine(str);
      }

      static void Main()
      {
         SaySomething("Hello to Sufyan");
         Console.ReadLine();
      }
   }
}

Here, when we call SaySomething(“Hello to Sufyan”), it will execute the code but in the output window a warning message will be displayed, showing us that the SaySomething method is obsolete.

Still, it doesn’t ask us to use the new talk method SaySomething instead. To display a customized message, we will customize the obsolete attribute like this:

[Obsolete("SaySomething() method is now Obsolete.
          Please use Talk()")]

By using this approach, we can add additional meaning to our attribute.

Note: We can have multiple attribute statements before a method or class. In such cases, if one of the statements is true, it will allow access to that particular method.

There are many attributes that come with DotNet.

  • Conditional
  • DllImport
  • Obsolete
  • Serializable

Conditional attribute

By using the Conditional attribute, we are following a scenario that if a particular condition is true, the user will have access to that specific method. Suppose you wanted your specific method to run only if Internet Explorer is found on the system. Applying this type of security on a method was not easy in the past. Now, it is possible by applying conditional attributes.

Case 2

Suppose you want a method to run if program is in Debug mode. We will write the conditional statement as follows:

[Conditional(.DEBUG.)]
public static void Help(String str)
{
   Console.WriteLine(str);
}

If one calls this method in Main(), it will run only if the program is in Debug mode. If you turn it off in the release mode, it will not run.

DLL Import

Before DotNet, if one wanted to access the core Windows API, he could add a reference and use the library provided by Windows SDK. In DotNet, if we want to access those core features of DotNet, we use DllImport. Component DLLs aren’t accessed this way. They are accessed by making a reference to them. Normal DLLs are accessed by using the DllImport attribute.

Case 3

using System;
System.Runtime.InteropServices;
class Beeper
{
   [DllImport(.kernel32.dll.)]
   Public static extern bool Beep(int frequency,int duration);
   static void Main()
   {
      Beep(1000,111);
   }
}

So far, we have learned how to use attributes in DotNet. Still, we haven’t learn how to create our own custom attributes with specified behaviour that we assign.

Steps in Creating a Custom Attribute

  1. Define the attribute’s usage.
  2. Extend our class with AttributeClass.
  3. Define the behaviours to the class.

Attribute behaviours can be of these types:

  • All—Any application element
  • Assembly—Attribute can be applied to an assembly
  • Class—Attribute can be applied to a class
  • Constructor—Attribute can be applied to a constructor
  • Delegate—Attribute can be applied to a delegate
  • Enum—Attribute can be applied to an enumeration
  • Event—Attribute can be applied to an event
  • Field—Attribute can be applied to a field
  • Interface—Attribute can be applied to an interface
  • Method—Attribute can be applied to a method
  • Module—Attribute can be applied to a module
  • Parameter—Attribute can be applied to a parameter
  • Property—Attribute can be applied to a property
  • ReturnValue—Attribute can be applied to a return value
  • Struct—Attribute can be applied to a structure

The second step is to extend the class with the Attribute class. Basically, our attribute is a class that defines the behaviours of our attribute. For example:

...
public class MySpecialAttribute:Attribute
{...

A point to be noted here is that the name of Attribute we are going to make is MySpecial. We didn’t suffix the word Attribute after MySpecial. DotNet automatically suffixed it.

Let us create a sample custom attribute that will execute the method if the regKey provided to the Attribute parameter is correct:

using System;
namespace RegKeyAttributeTestor
{
   [AttributeUsage(AttributeTargets.Method|AttributeTargets.Struct,
                   AllowMultiple=false,Inherited=false]
   public class MyAttribute:Attribute
   {
      private string regKey="a12nf";
      public MyAttribute(string regKey)
      {
         if(this.regKey==regKey)
         {
            Console.WriteLine("Permitted to use this App");
         }
         else
         {
            Console.WriteLine("Not registered to use this App");
         }
      }
   }    //End Attribute class code
   class useAttrib
   {
      [MyAttribute("hello")]
      public static string SayHello(string str)
      {
         return str;
      }
      static void Main()
      {
         Console.WriteLine(SayHello("Hello to Sufyan"));
         Console.ReadLine();
      }
   }

}
AttributeUsage(AttributeTargets.Method|AttributeTargets.Struct,
               AllowMultiple=false, Inherited=false)]

Here, multiple Attribute targets are declared by using “|” between different targets. Allows multiple=false means multiple attributes can be used with this attribute. Inherited=false shows that if some class extends a class that uses this attribute and calls a method that is bound to this attribute, that class has no access to this attribute unless this property is set to true.

Reading Metadata from Assemblies

We first write our custom attribute:

using System;

namespace Sufyan
{
   [AttributeUsage(AttributeTargets.Method,AllowMultiple=false,
                   Inherited=false)]
   public class RegKeyAttribute : Attribute
   {
      private string regKey;

      public RegKeyAttribute(string VRegKey)
      {
         this.regKey = VRegKey;
         if (this.regKey==.hello.)
         {
            Console.WriteLine("Aha! You're Registered");
         }
         else
         {
            Console.WriteLine("Oho! You're not Registered");
         }
      }
   }
}

Now, we shall write our code to reference it through Assembly;.

Steps

First, compile the first example as a Class library; it will generate a .dll file. We will place this .dll file in the bin folder of our second example we are going to make now.

using System;
using System.Reflection;
using Sufyan;

namespace AdvancedDotNet1
{
   class Classic
   {
      static void Main(string[] args)
      {
         Assembly suf = Assembly.Load("RegKey");
         Type KIA=suf.GetType();
         []KO=Attribute.GetCustomAttributes(KIA);
         Object Regist =KO[0];
         Console.WriteLine("Registeration Code is :"+
                           Regist.ToString() );
         Console.ReadLine();
      }
   }
}

System.Reflection is used to retrieve info from the assembly metadata.

To use this in another class, verify that a specific method will execute if that particular developer is registered with me and I have issued him the license key to use.

class useAttrib
   {
      [RegKeyAttribute ("hello")]
      public static string SayHello(string str)
      {
         return str;
      }
      static void Main()
      {
         Console.WriteLine(SayHello("Hello to Sufyan"));
         Console.ReadLine();
      }
   }

Have a close look at this code. I have provided the Hello string as a parameter to the attribute. When we run this application, if we pass a string other then “hello”, it will say that you are not registered. We can further modify it according to our need.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read