Posts Tagged Attribute

C# Tribal Knowledge: Use of the Conditional Attribute for Conditional Compilation For Object and and Argument Validation during Development

stockxpertcom_id14589271_jpg_013ced4118ce4854e1935aeaa12684ecThis is another one of of my topics which I deem to be Tribal Knowledge type information. For me it seems that such information seems be known by only the privileged few. In this article I present for your reading perusal details on how to handle different state errors found in classes and arguments during debug/development activities. The premise is that such checks for object or argument correctness is only needed for development and not for production level code. By using the Conditional attribute in ones C# code such checks can be utilized for object and state correctness but not be a burden in a production program or web site.

Development State Errors Checking

For example, and yes its a basic example,  say one is writing a database layer and the requirement is that the connection string be be properly filled with with a database name a user name and a password. You happen to know that this code will be reused by others on the development staff and they will most likely fail to provide such values the first time they hook up the code. So you don’t have to go to their desks to hand hold and debug the error, wouldn’t it be nice if the object checked its own state of correctness?

Once working the checks will really become superfluous and will be removed. This scenario speaks to the fact that the user has two options, or two roads to failure, of loading the values. Say it can be done either during construction or after via the exposed properties. Just ripe for someone to forget to do one or the other.

Code Speaks Conditionally

For the code we will create a connection object which checks for the validity, to the best of its ability, of those values before their use, and if a problem exists throw an application exception during development time only.

Here is our code and the highlight lines are related to the state checking:

using System.Diagnostics;

public class ConnectionManager
{
    public string DatabaseName { get; set; }
    public string UserName     { get; set; }
    public string Password     { get; set; }

    public ConnectionManager() { }

    public ConnectionManager( string databaseName, string userName, string password )
    {
        DatabaseName = databaseName; UserName = userName; Password = password;
    }

    public string GenerateConnectionString()
    {
        // This is only called during debug builds and *not compiled*
        ValidateState(); // during Release builds.

        return string.Format( "{0};User={1};Password={2}", DatabaseName, UserName, Password );
    }

    [Conditional( "Debug" )]
    private void ValidateState()
    {
        if ( string.IsNullOrEmpty( DatabaseName ) )
            throw new ApplicationException( "Development Error: DatabaseName Empty" );

        if ( string.IsNullOrEmpty( UserName ) )
            throw new ApplicationException( "Development Error: UserName Empty" );

        if ( string.IsNullOrEmpty( Password ) )
            throw new ApplicationException( "Development Error: Password Empty" );

    }

}

So if this class is instantiated and the proper variables are not setup an application exception is thrown during debug mode only when a call to generate a connection string occurs. The magic is done by the highlighted lines but the second one with Conditional attribute tells the compiler to only use this in debug builds

Summary

Now this example is a bit contrived, but the idea is that if one has unique business state requirements which may need to be met before an object’s operation can be used, this methodology can be used to catch all actions, but not hamper runtime operations. It obviously shouldn’t be used to catch unique runtime scenarios such as user validation, those should be handled directly and possibly not by generating an exception.

Share

Tags: , ,

C# Using Extended Attribute Information on Objects

Update 5/26/2014 : Added Enum Extension to Extract Custom Attribute.

I use this trick in .Net to extensively Trojan Horse extra meta type information on any object. At run time I reflect off of the object and extract this information which was placed on it. Below I show how to do it on an enum using a built in attribute in .Net and secondly I show how to create your own custom attribute. Note: in the example is an enum, but one can decorate any object with the attribute.

Single Attribute Values

The first way which will be shown is done using C#’s description attribute found in the System.ComponentModel namespace and does not require any special coding such as creating a class definition for the attribute. The second way shows a more robust custom attribute which has more specialized information.

Step 1 Include these namespaces:

using System.Reflection;
using System.ComponentModel;

Step 2 Decorate the enums with the Description Attribute

public enum EPortalErrors
{
  [Description("Internal programming error")]
  InternalError,
  [Description("Invalid request Xml: Reset XSLT.")]
  InvalidXmlSentIn,
}

Step 3 Create a static method to divine the attribute description

/// <summary>If an attribute such as is on an enumeration exists, this will return that
/// information</summary>
/// <param name="value">The object which has the attribute.</param>
/// <returns>The description string of the attribute or string.empty</returns>
public static string GetAttributeDescription( object value )
{
    string retVal = string.Empty;
    try
    {
        FieldInfo fieldInfo = value.GetType().GetField(value.ToString());

        DescriptionAttribute[] attributes =
           (DescriptionAttribute[])fieldInfo.GetCustomAttributes
           (typeof(DescriptionAttribute), false);

        retVal = ( ( attributes.Length > 0 ) ? attributes[0].Description : value.ToString() );
    }
    catch (NullReferenceException)
    {
     //Occurs when we attempt to get description of an enum value that does not exist
    }
    finally
    {
        if (string.IsNullOrEmpty(retVal))
            retVal = "Unknown";
    }    

    return retVal;
}

Step 4 Call GetAttributeDescription with the enum in hand and we will get the extended text. Done…


Multiple Attribute Values

That first method is is nice for basic information, but what if one needs more information? That can be done by writing a custom attribute information extraction class. We will start at step 2 from above:

Step 2 Determine what items should be on the attribute and create an attribute name. In the below example we want to decorate the enum with three integers and another enum. This extended information will allow for other processing to occur which is dependant on that info. Our attribute name is DatabaseConnection which will mirror our attribute extraction class

public enum EActivities
{
   HoldingsGet,

    /// <summary>We need to inform the DAL that the primary keys are 1,2,3 and
    /// that we only want one column</summary>
   [DatabaseConnection(1,2,3, DatabaseConnectionAttribute.Columns.OneColumn)]
   OpsDBAttributionBatchCodes,
}

Step 3 Create a static method to divine the attribute description for DatabaseConnection. Note there is other activities/properties that are shown, for the consumer can get the extended int info in a list. Note also we have to decorate the class with an attribute to let the system know that this class will be used as an attribute

/// <summary>When using Enums for exceptions this attribute provides more information
/// to describe the enumeration such as target fields and primary keys.</summary>
[AttributeUsage(AttributeTargets.Field)]
public class DatabaseConnectionAttribute : Attribute
{

    #region Construction    

    /// <summary>Used to specify the needed columns.</summary>
    public enum Columns : int
    {
        OneColumn = 1,
        TwoColumns = 2,
        ThreeColumns = 3,
        FourColumns = 4,
        FiveColumns = 5,
        SixColumns = 6
    }

    /// <summary>Allow a consumer to specify an attribute with for data items.</summary>
    public DatabaseConnectionAttribute(int pkey1, int pkey2, int pkey3, DatabaseConnectionAttribute.Columns columns)
    {
        pkeys.Add(pkey1);
        pkeys.Add(pkey2);
        pkeys.Add(pkey3);
        _Columns = columns;
    }

    #endregion
    #region Properties
    /// <summary>To total number of columns to extract from the database.</summary>
    public DatabaseConnectionAttribute.Columns ColumnsNeeded
    {
        get { return _Columns; }
    }    

    /// <summary>Retrieves the list of primary keys.</summary>
    public List<int> PrimaryKeys
    {
        get { return pkeys; }
    }

    #endregion    

    #region Exposed Static Functionality

    /// <summary>This method will peer into an enum and extract this class if it exists.</summary>
    /// <param name="enumItem">The enumeration which contains the DatabaseConnectionAttribute.</param>
    /// <returns>The current object or null</returns>
    public static DatabaseConnectionAttribute ExtractAttribute(object enumItem)
    {
        DatabaseConnectionAttribute retVal = null;

        try
        {
            FieldInfo fieldInfo = enumItem.GetType().GetField(enumItem.ToString());
            DatabaseConnectionAttribute[] attributes =
                (DatabaseConnectionAttribute[])fieldInfo.GetCustomAttributes
                (typeof(DatabaseConnectionAttribute), false);

            if (attributes != null)
                if (attributes.Length > 0)
                    retVal = attributes[0];
        }
        catch (NullReferenceException)
        {
            //Occurs when we attempt to get description of an enum value that does not exist
        }

        return retVal;
    }
    #endregion

    #region Variables
    /// <summary>Holds the primary key information.</summary>
    List<int> pkeys = new List<int>();    

    /// <summary>What columns are required by the user.</summary>
    private DatabaseConnectionAttribute.Columns _Columns;
    #endregion

}

Step 4 Now by calling the static ExtractAttribute we are returned an object that has all of the information off of the enum. Quite handy.


 

Update: Extracting Custom Attribute using a Generic Extension.

Use this code to extract your custom extension. In the below example we use the custom extension to get the custom attribute, of the enum defined above and its custom attribute.

DatabaseConnectionAttribute custAttr = 

    EActivities.OpsDBAttributionBatchCodes
               .ExtractAttribute<DatabaseConnectionAttribute, EActivities>();

Extension Method Code

/// <summary>
/// If an enum has a custom attrbute, this will returrn that attribute or null.
/// </summary>
/// <typeparam name="TCustomAttr">The type of the custom attribute to extract from the enum.</typeparam>
/// <typeparam name="TEnumItance">The enum currently being viewed..</typeparam>
/// <param name="instance">The instance.</param>
/// <returns>The custom attribute (TCustomAttr) or null</returns>
public static TCustomAttr ExtractAttribute<TCustomAttr, TEnum>(this TEnum instance)
{
    if (instance != null)
    {
        try
        {
            FieldInfo fieldInfo = instance.GetType()
                                          .GetField(instance.ToString());

            var attributes = fieldInfo.GetCustomAttributes(typeof(TCustomAttr), false)
                                      .ToList();

            if (attributes.Any())
                return (TCustomAttr)attributes[0];

        }
        catch (Exception)
        {
        }
    }

    return default(TCustomAttr);
}
Share

Tags: