I Prefer Jim Developer James Schubert shares his code and his thoughts.

26May/10

System.ComponentModel.DataAnnotations for ASP.NET Web Forms

Although I'm primarily an ASP.NET Web Forms developer, I regularly dabble in new and interesting technologies.  I've toyed with other Microsoft technologies such as ASP.NET MVC and Dynamic Data web sites.

ASP.NET MVC offers an interesting mechanism for validating view models called DataAnnotations.   Examples can be seen here and here.

Some of the more useful attributes for validation include:

  • RequiredAttribute
  • RegularExpressionAttribute
  • RangeAttribute
  • DataTypeAttribute

I recently decided to implement a data validation schema (for lack of a better term) for web forms similar to that of ASP.NET MVC. This would allow us to maintain validation of a model object via attributes at the class level, instead of dispersing these validation rules through the web form code or any of the business logic layers. However, there will be occasions where an object's validity depends upon some state or validity of another object. I've handled this by allowing the validation method to accept any action to be called after the object has been validated.

In order to make a domain object validatable, I'm going to implement the following interface:

IValidatable.cs

namespace Validatable
{
    interface IValidatable
    {
        System.Type EntityType { get; set; }
        System.Collections.Generic.List<object> Errors { get; set; }

        /// <summary>
        /// Determine whether the object is valid.  If invalid, errors are added to item.Errors
        /// </summary>
        /// <returns>true if valid, false if invalid</returns>
        bool IsValid();

        /// <summary>
        /// Validate this item against a supplied action
        /// </summary>
        /// <param name="action">The action to use for validation</param>
        void Validate(System.Action action);

        /// <summary>
        /// Validate this object against a Repository.
        /// <example>
        /// Item a = new Item();
        /// a.Validate(new ItemRepository());
        /// </example>
        /// Note: Repository must have a Validate(T item) method
        /// </summary>
        /// <param name="repository">The Repository to use for validation</param>
        void Validate(object repository);
    }
}

As you can see, this abstract class adds a property accessor for the entity's type, a list of validation errors, an IsValid method, and two Validate methods.

Validatable<T>

I'll take the code in chunks, since there is a lot more than I usually post.
First of all, the using directives required for this class are pretty sparse:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Reflection;

The class definition is:

   [Serializable]
    public abstract class Validatable<T> : IValidatable where T : class, new()
    { /* class */ }

If you're unfamiliar with generic constraints, the where T : class, new() above enforces the T passed as in to be a class and to have a parameterless constructor (new())

The properties can be auto-implemented properties, or they can implement any backing logic you prefer. The constructor as I have it is:

 protected Validatable()
 {
     Errors = new List<object>();
     EntityType = typeof(T);
 }

Now for the methods and a slight explanation of each:

IsValid()

        public virtual bool IsValid()
        {
            Errors = new List<object>();
            PropertyInfo[] props = this.GetType().GetProperties();

            foreach (PropertyInfo property in props)
            {
                foreach (ValidationAttribute va in
                    property.GetCustomAttributes(true).OfType<ValidationAttribute>())
                {
                    var value = property.GetValue(this, null);
                    if (!va.IsValid(value))
                    {
                        Errors.Add(va.ErrorMessage);
                    }
                }
            }

            return Errors.Count <= 0;
        }

As a side note, all DataAnnotation attributes inherit from ValidationAttribute. You can create your own Validation Attributes by inheriting from this class. This method clears the list of errors and repopulates it by looping over any properties with validation attributes of this object, validates that property's value against the attribute, and adds the ErrorMessage associated with it to the list of Errors.

Validate Methods

        public virtual void Validate(Action action)
        {
            if (IsValid())
            {
                action();
            }
        }

        public virtual void Validate(object repository)
        {
            MethodInfo method = repository.GetType().GetMethods()
                .Where(x => x.Name.Equals("Validate")).FirstOrDefault();
            if (method != null)
            {
                object[] parameters = new object[] { this };
                Validate(() => method.Invoke(repository, parameters));
            }
        }

These two methods can be changed to throw an exception if the object is invalid. I'll leave that up to you. The way these are set up is to allow you to validate the object and perform either some unknown action or call Validate(T item) against some other object, arbitrarily called a repository. In actuality, you could have a Validate method on some other object that takes an object of this type and essentially chain validations.

The simplicity of the Validate(Action action) method is what makes it beautiful. For instance, you can have an item (a) and cause it save after validation by doing something like:

a.Validate(() => new ItemDAL().Save(a));

As you can see, a Save method in your Item's Data Access Layer taking Item as a parameter can be called only when a.IsValid() is true. Again, there are a number of ways to tweak this and change it to your liking, but I'll leave that up to you.

DataAnnotationValidator

Here is the wonderful part about all of this. You can create a custom validator that validates in a similar way as the Validatable class. I'll post the code and quickly explain what it does. I got the idea from this from another blog and tweaked it a little.

DataAnnotationValidator.cs

// DataAnnotationValidator.cs
namespace Validatable
{
    using System;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Reflection;
    using System.Web.UI;
    using System.Web.UI.WebControls;

    [ToolboxData("<{0}:DataAnnotationValidator runat=\"server\" ControlToValidate=\"[Required]\" Display=\"Dynamic\" Text=\"*\" SourceTypeName=\"[FullyQualifiedTypeName]\" PropertyToValidate=\"[PropertyName]\" />")]
    public class DataAnnotationValidator : BaseValidator
    {
        /// <summary>
        /// THe Property that should be checked
        /// </summary>
        public string PropertyToValidate { get; set; }

        /// <summary>
        /// The object's type
        /// </summary>
        public string SourceTypeName { get; set; }

        protected override bool EvaluateIsValid()
        {
            Type source = GetValidatedType();
            PropertyInfo property = GetValidatedProperty(source);
            string value = GetControlValidationValue(ControlToValidate);

            foreach (ValidationAttribute va in property
                .GetCustomAttributes(typeof(ValidationAttribute), true)
                .OfType<ValidationAttribute>())
            {
                if (!va.IsValid(value))
                {
                    if (string.IsNullOrEmpty(ErrorMessage))
                    {
                        this.ErrorMessage = va.ErrorMessage;
                    }
                    return false;
                }
            }

            return true;
        }

        private Type GetValidatedType()
        {
            if (string.IsNullOrEmpty(SourceTypeName))
            {
                throw new InvalidOperationException("Null SourceTypeName can't be validated");
            }

            Type validatedType = Type.GetType(SourceTypeName);
            if (validatedType == null)
            {
                throw new InvalidOperationException(
                    string.Format("{0}:{1}", "Invalid SourceTypeName", SourceTypeName));
            }

            return validatedType;
        }

        private PropertyInfo GetValidatedProperty(Type source)
        {
            PropertyInfo property = source.GetProperty(PropertyToValidate,
              BindingFlags.Public | BindingFlags.Instance);

            if (property == null)
            {
                throw new InvalidOperationException(
                  string.Format("{0}:{1}", "Validated Property Does Not Exists", PropertyToValidate));
            }
            return property;
        }
    }
}

This creates a validator web control which has 'PropertyToValidate' and 'SourceTypeName'. When a Validator web control is added to a page, it must have ControlToValidate, PropertyToValidate, and SourceTypeName specified or an error will be thrown. The validation method verifies the type and the property, gets the value of the property and finally, much like the Validatable abstract class, it loops over all ValidationAttributes and validates the value against that attribute. You can use this with multiple attributes, so it doesn't hurt to add this validator to a property-- that just means you can add an attribute in the future and everything is already wired up! That's pretty cool.

Example

As an example, I'm going to create a single page to **input** a Customer object. The customer object is very simple:

 public class Customer : Validatable.Validatable<Customer>
    {
        [Required(ErrorMessage="UserId is Required")]
        public int UserId { get; set; }

        [DataType(DataType.PhoneNumber, ErrorMessage="Invalid Phone Number")]
        public string PhoneNumber { get; set; }

        [RegularExpression(@"(^\d{5}(-\d{4}){0,1}$)", ErrorMessage="Invalid Zip Code")]
        public string ZipCode { get; set; }
    }

And the Page in full is collapsed below:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Example._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <asp:Label ID="lblStatus" runat="server" />
    <asp:ValidationSummary ID="ValidationSummary1" runat="server" />
    <div>
        <asp:FormView ID="FormView1" runat="server" DataSourceID="srcRepository"
            Width="119px" AllowPaging="True">
            <EditItemTemplate>
                UserId:
                <asp:TextBox ID="UserIdTextBox" runat="server" Text='<%# Bind("UserId") %>' />
                <example:DataAnnotationValidator ID="DataAnnotationValidator1" runat="server" ControlToValidate="UserIdTextBox" Display="Dynamic"
                    PropertyToValidate="UserId" ErrorMessage="Invalid User Identification Number"
                    SourceTypeName="Example.Customer, Example, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
                    Text="*"/>
                <br />
                PhoneNumber:
                <asp:TextBox ID="PhoneNumberTextBox" runat="server"
                    Text='<%# Bind("PhoneNumber") %>' />
                <example:DataAnnotationValidator ID="DataAnnotationValidator2" runat="server" ControlToValidate="PhoneNumberTextBox" Display="Dynamic"
                    PropertyToValidate="PhoneNumber" OnInit="GetTypeName" SourceTypeName="Example.Customer, Example, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" Text="*"/>
                <br />
                ZipCode:
                <asp:TextBox ID="ZipCodeTextBox" runat="server" Text='<%# Bind("ZipCode") %>' />
                <example:DataAnnotationValidator ID="DataAnnotationValidator3" runat="server" ControlToValidate="ZipCodeTextBox" Display="Dynamic"
                    PropertyToValidate="ZipCode" SourceTypeName="Example.Customer, Example, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" Text="*"/>
                <br />
                EntityType:
                <asp:TextBox ID="EntityTypeTextBox" runat="server"
                    Text='<%# Eval("EntityType") %>' />
                <br />
                <asp:LinkButton ID="UpdateButton" runat="server" CausesValidation="True"
                    CommandName="Update" Text="Update" />
                &nbsp;<asp:LinkButton ID="UpdateCancelButton" runat="server"
                    CausesValidation="False" CommandName="Cancel" Text="Cancel" />
            </EditItemTemplate>
            <InsertItemTemplate>
                UserId:
                <asp:TextBox ID="UserIdTextBox" runat="server" Text='<%# Bind("UserId") %>' />
                <example:DataAnnotationValidator ID="DataAnnotationValidator1" runat="server" ControlToValidate="UserIdTextBox" Display="Dynamic"
                    PropertyToValidate="UserId"  OnInit="GetTypeName"  Text="*"/>
                <br />
                PhoneNumber:
                <asp:TextBox ID="PhoneNumberTextBox" runat="server"
                    Text='<%# Bind("PhoneNumber") %>' />
                <example:DataAnnotationValidator ID="DataAnnotationValidator2" runat="server" ControlToValidate="PhoneNumberTextBox" Display="Dynamic"
                    PropertyToValidate="PhoneNumber" OnInit="GetTypeName"  Text="*"/>
                <br />
                ZipCode:
                <asp:TextBox ID="ZipCodeTextBox" runat="server" Text='<%# Bind("ZipCode") %>' />
                <example:DataAnnotationValidator ID="DataAnnotationValidator3" runat="server" ControlToValidate="ZipCodeTextBox" Display="Dynamic"
                    PropertyToValidate="ZipCode" OnInit="GetTypeName"  Text="*"/>
                <br />
                EntityType:
                <asp:TextBox ID="EntityTypeTextBox" runat="server"
                    Text='<%# Eval("EntityType") %>' />
                <br />
                <asp:LinkButton ID="InsertButton" runat="server" CausesValidation="True"
                    CommandName="Insert" Text="Insert" />
                &nbsp;<asp:LinkButton ID="InsertCancelButton" runat="server"
                    CausesValidation="False" CommandName="Cancel" Text="Cancel" />
            </InsertItemTemplate>
            <ItemTemplate>
                UserId:
                <asp:Label ID="UserIdTextBox" runat="server" Text='<%# Bind("UserId") %>' />
                <br />
                PhoneNumber:
                <asp:Label ID="PhoneNumberTextBox" runat="server"
                    Text='<%# Bind("PhoneNumber") %>' />
                <br />
                ZipCode:
                <asp:Label ID="ZipCodeTextBox" runat="server" Text='<%# Bind("ZipCode") %>' />
                <br />
                EntityType:
                <asp:Label ID="EntityTypeLabel" runat="server"
                    Text='<%# Bind("EntityType") %>' />
                <br />
                <asp:LinkButton ID="EditButton" runat="server" CausesValidation="False"
                    CommandName="Edit" Text="Edit" />
                &nbsp;<asp:LinkButton ID="NewButton" runat="server" CausesValidation="False"
                    CommandName="New" Text="New" />
            </ItemTemplate>
        </asp:FormView>
        <asp:ObjectDataSource ID="srcRepository" runat="server"
            DataObjectTypeName="Example.Customer" InsertMethod="Save"
            oninserted="srcRepository_Saved" onupdated="srcRepository_Saved"
            SelectMethod="Get" TypeName="Example.CustomerRepository" UpdateMethod="Save"></asp:ObjectDataSource>
    </div>
    </form>
</body>
</html>

Of particular note here is in the EditTemplate, you'll see

                  UserId:
                <asp:TextBox ID="UserIdTextBox" runat="server" Text='<%# Bind("UserId") %>' />
                <example:DataAnnotationValidator ID="DataAnnotationValidator1" runat="server" ControlToValidate="UserIdTextBox" Display="Dynamic"
                    PropertyToValidate="UserId" ErrorMessage="Invalid User Identification Number"
                    SourceTypeName="Example.Customer, Example, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
                    Text="*"/>

in which the SourceTypeName must be the full Assembly Qualified Name. This is necessary if the Validatable and DataAnnotationValidator classes are in an external library. This is a rather tedious property to fill for each validator. Another way to get around this is to populate the SourceTypeName as seen in the InserItemTemplate, e.g.

                UserId:
                <asp:TextBox ID="UserIdTextBox" runat="server" Text='<%# Bind("UserId") %>' />
                <example:DataAnnotationValidator ID="DataAnnotationValidator1" runat="server" ControlToValidate="UserIdTextBox" Display="Dynamic"
                    PropertyToValidate="UserId"  OnInit="GetTypeName"  Text="*"/>

and the code in the code behind is very simple:

        protected void GetTypeName(object sender, EventArgs e)
        {
            DataAnnotationValidator validator = (DataAnnotationValidator)sender;
            validator.SourceTypeName = new Customer().EntityType.AssemblyQualifiedName;
        }

Also notice that the first validator (the one with the assembly qualified name) has an ErrorMessage property specified. Doing this allows you to override the error message returned from the validated object. We can do this if the model says "UserId" and you want the user to see this property referred to as "User Identification".

Conclusion

Sometimes dabbling in other technologies can open the door for new and simpler ways of doing things. I like this example because it allows you to build web applications quickly and easily, while making them maintainable in the future (new validations only have to be added to the model, not to every control where the model must be validated).

For further reference, this project is linked below. Please download and modify if necessary.
Validatable.zip

4May/10

Finding a user’s local time from UTC offset

I answered a question over at StackOverflow, and I really liked the answer, so I thought I would share this nifty extension method:


        /// <summary>
        /// Convert a given DateTime object to a user's local time,
        /// taking into account changes in TimeZone rules.
        /// For example, if you were to perform this operation on
        /// a time now, during EST Daylight Saving, and that time falls
        /// outside the scope of Daylight Saving time, the rule will adjust accordingly.
        /// </summary>
        /// <param name="dateTime">The DateTime object</param>
        /// <param name="offset">offset from UTC</param>
        /// <returns>User's local time</returns>
        public static DateTime ConvertToLocalDateTime(this DateTime dateTime, int offset)
        {
            TimeZoneInfo destinationTimeZone = TimeZoneInfo.GetSystemTimeZones()
               .Where(x => x.BaseUtcOffset.Hours.Equals(offset)).FirstOrDefault();

            var rule = destinationTimeZone.GetAdjustmentRules().Where(x =>
                x.DateStart <= dateTime && dateTime <= x.DateEnd)
                .FirstOrDefault();

            TimeSpan baseOffset = TimeSpan.Zero;
            if (rule != null)
            {
                baseOffset -= destinationTimeZone.IsDaylightSavingTime(dateTime) ?
                    rule.DaylightDelta : TimeSpan.Zero;
            }

            DateTimeOffset dto = DateTimeOffset.Parse(dateTime.ToString());
            return new DateTime(TimeZoneInfo
                     .ConvertTimeFromUtc(dateTime,
                            destinationTimeZone).Ticks + baseOffset.Ticks);
        }

The summary basically says it all. I ran through a couple of tests with this, I'd like to know if anyone uses this and makes modifications to it!

3May/10

NHibernate.Criterion Extensions workaround

I've been working with Fluent NHibernate for the past month or so, and I realized while writing an NHibernate query that the NHibernate Criterion's Restrictions class isn't very refactor-friendly. The refactorability of Fluent NHibernate is ultimately why we've decided to use it. It does take a little longer to set up than some other ORMs, but in the long-run it's nice to be able to change a property name and refactor.

... except the property names are hard-coded in the Criteria!

My workaround for this is to use a bit of static reflection a-la-FNH, and maintain code that is easily refactored.

For instance, I've created a static utility class (Showing the Restrictions.Eq() substitute):

  public static class CriterionExtensions
    {
        public static SimpleExpression Eq<T>(
                Expression<Func<T, object>> exp, object value
        )
        {
            var memberExpression = GetMemberExpression(exp);
            string propertyName = ((PropertyInfo)memberExpression.Member).Name;
            if (!string.IsNullOrEmpty(propertyName))
                return Restrictions.Eq(propertyName, value);
            else
                return null;
        }

        private static MemberExpression GetMemberExpression<T>(
                Expression<Func<T, object>> expression
        )
        {
            MemberExpression memberExpression = null;
            if (expression.Body.NodeType == ExpressionType.Convert)
            {
                var body = (UnaryExpression)expression.Body;
                memberExpression = body.Operand as MemberExpression;
            }
            else if (expression.Body.NodeType == ExpressionType.MemberAccess)
            {
                memberExpression = expression.Body as MemberExpression;
            }
            if (memberExpression == null)
            {
                throw new ArgumentException("Not a member access", "member");
            }
            return memberExpression;
        }
    }

And to use this code, you can create an aliased using directive and call it in code:

    using Ensure = MyNamespace.Extensions.Criterion.CriterionExtensions;
    /* class declarations and whatnot */
     internal IEnumerable<Product> GetAll(int shelfNumber)
      {
          var session = SessionManager.GetCurrentSession();
          return session.CreateCriteria<Product>()
              .Add(Ensure.Eq<Product>(x => x.ShelfNumber, shelfNumber))
              .List<Product>();
      }

It's pretty simple to use and is easily refactored. You may be able to add your *extensions* to a namespace: NHibernate.Criterion and call your class Restrictions, but I didn't try this (I don't like mixing namespaces). Let me know what you think!

3May/10

CopyCat Rails’ Time Extensions

I've become a fan of Ruby's simple syntax. My favorite thing is the ActiveSupport's Numeric Time Extensions. I'm starting a library of useful extensions, and I'm going to be adding a number of shortcuts to mock these extensions.

For those of you that don't want to follow the link, check out the syntax:

  # equivalent to Time.now.advance(:months => 1)
  1.month.from_now

  # equivalent to Time.now.advance(:years => 2)
  2.years.from_now

  # equivalent to Time.now.advance(:months => 4, :years => 5)
  (4.months + 5.years).from_now

Here is what I've gotten so far (it only includes int for now):

public static class DateExtensionsThatMockRuby
    {
        /// <summary>
        /// Retrieve the number of ticks for x Days.
        /// <example>long ticks = 5.Days();</example>
        /// </summary>
        /// <param name="i"></param>
        /// <returns>ticks</returns>
        public static long Days(this int i)
        {
            return new TimeSpan(i, 0, 0, 0).Ticks;
        }

        /// <summary>
        /// Retrieve the number of ticks for x Hours.
        /// </summary>
        /// <example>long ticks = 15.Hours();</example>
        /// <param name="i"></param>
        /// <returns>ticks</returns>
        public static long Hours(this int i)
        {
            return new TimeSpan(0, i, 0, 0).Ticks;
        }

        /// <summary>
        /// Retrieve the number of ticks for x Minutes
        /// </summary>
        /// <example>long ticks = 97.Minutes();</example>
        /// <param name="i"></param>
        /// <returns>ticks</returns>
        public static long Minutes(this int i)
        {
            return new TimeSpan(0, i, 0).Ticks;
        }

        /// <summary>
        /// Retrieve the number of ticks for x Seconds
        /// </summary>
        /// <example>long ticks = 3000.Seconds();</example>
        /// <param name="i"></param>
        /// <returns>ticks</returns>
        public static long Seconds(this int i)
        {
            return new TimeSpan(0, 0, i).Ticks;
        }

        /// <summary>
        /// Retrieve the number of ticks for x Milliseconds
        /// </summary>
        /// <example>long ticks = 3000.Milliseconds();</example>
        /// <param name="i"></param>
        /// <returns>ticks</returns>
        public static long Milliseconds(this int i)
        {
            return new TimeSpan(0, 0, 0, 0, i).Ticks;
        }

        /// <summary>
        /// Retrieve a DateTime object from ticks
        /// <example>DateTime dt = 236423690923466.AsDateTime();</example>
        /// /// <example>DateTime dt = 10.Days().AsDateTime();</example>
        /// </summary>
        /// <param name="ticks"></param>
        /// <returns>DateTime</returns>
        public static DateTime AsDateTime(this long ticks)
        {
            return new DateTime(ticks);
        }

        /// <summary>
        /// Retrieve a DateTime object from ticks
        /// <example>DateTime dt = 236423690923466.AsDateTime(DateTimeKind.Utc);</example>
        /// /// <example>DateTime dt = 10.Days().AsDateTime(DateTimeKind.Utc);</example>
        /// </summary>
        /// <param name="ticks"></param>
        /// <returns>DateTime</returns>
        public static DateTime AsDateTime(this long ticks, DateTimeKind kind)
        {
            return new DateTime(ticks, kind);
        }
    }
Tagged as: , , No Comments
22Apr/10

DRY! GenericComparer for sorting Generic Lists

I'm a pretty firm believer in the Ruby/Ruby on Rails idea of DRY ("Don't Repeat Yourself").

That said, I get pretty tired of writing comparers for sorting lists and generic lists. Every one of these comparers is exactly the same: you specify a list of properties related to the object and a sort direction, then call compare on those properties.

This can be changed with a little reflection:

   public class GenericComparer<T> : IComparer<T>
    {
        public string SortExpression { get; set; }
        public int SortDirection { get; set; } // 0:Ascending, 1:Descending

        public GenericComparer(string sortExpression, int sortDirection)
        {
            this.SortExpression = sortExpression;
            this.SortDirection = sortDirection;
        }
        public GenericComparer() { }

        #region IComparer<T> Members
        public int Compare(T x, T y)
        {
            PropertyInfo propertyInfo = typeof(T).GetProperty(SortExpression);
            IComparable obj1 = (IComparable)propertyInfo.GetValue(x, null);
            IComparable obj2 = (IComparable)propertyInfo.GetValue(y, null);

            if (SortDirection == 0)
            {
                return obj1.CompareTo(obj2);
            }
            else return obj2.CompareTo(obj1);
        }
        #endregion
    }

This is a code snippet I love to have in my arsenal.

Here's how you use it:

List<MyObject> objectList = GetObjects(); /* from your repository or whatever */
objectList.Sort(new GenericComparer<MyObject>("ObjectPropertyName", (int)SortDirection.Descending));
dropdown.DataSource = objectList;
dropdown.DataBind();

Note that Sort returns void. This means you can't throw this to the right of a DataSource call. You'd have to call this, then call your DataSource/DataBind.

Tagged as: , , No Comments
21Mar/10

String Concatenation in .NET – what really goes on?

There are a number of ways to concatenate a string in C# and other .NET languages. Is there a *best* way?

Let's look at how the C# compiler translates our code into IL to see the differences.

Here is a simple little console application to concatenate a string via String.Concat, String.Format, System.String's (+) operator, System.String's Join, and StringBuilder's Append method.


    class Program
    {
        static void Main(string[] args)
        {
            string first = "The cake";
            string second = " is a";
            string third = " lie.";

            string fromConcat = Concat(first, second, third);
            string fromFormat = Format(first, second, third);
            string fromPluses = Pluses(first, second, third);
            string fromBuilder = Builder(first, second, third);
            string fromJoiner = Joiner(first, second, third);

            Console.WriteLine(fromConcat);
            Console.WriteLine(fromFormat);
            Console.WriteLine(fromPluses);
            Console.WriteLine(fromBuilder);
            Console.WriteLine(fromJoiner);

            Console.ReadLine();
        }

        static string Concat(params string[] strings)
        {
            return String.Concat(strings);
        }

        static string Format(params string[] strings)
        {
            return string.Format("{0}{1}{2}", strings);
        }

        static string Pluses(params string[] strings)
        {
            return strings[0] + strings[1] + strings[2];
        }

        static string Builder(params string[] strings)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(strings[0]);
            sb.Append(strings[1]);
            sb.Append(strings[2]);
            return sb.ToString();
        }

        static string Joiner(params string[] strings)
        {
            return string.Join("", strings);
        }
    }

Which of these do you think will require the most intermediary code? I'd say it's StringBuilder, since we have to instantiate an object and call a method on that object a number of times. I'd like to go over these individually. The code in Main() works the same for all methods: a new string array is created and passed to the method which returns a string into a new variable. Here are the methods:

Concat

  .method private hidebysig static string
          Concat(string[] strings) cil managed
  {
    .param [1]
    .custom instance void [mscorlib]System.ParamArrayAttribute::.ctor() = ( 01 00 00 00 ) // Code size       12 (0xc)
    .maxstack  1
    .locals init ([0] string CS$1$0000)
    IL_0000:  nop
    IL_0001:  ldarg.0
    IL_0002:  call       string [mscorlib]System.String::Concat(string[])
    IL_0007:  stloc.0
    IL_0008:  br.s       IL_000a
    IL_000a:  ldloc.0
    IL_000b:  ret
  } // end of method Program::Concat

The C# compiler converts String.Concat into the smallest amount of code, and (I assume), the best as far as performance. It couldn't get any simpler than this method: it loads the arguments, passes them to the method, stores that result in memory and returns.

Format

  .method private hidebysig static string
          Format(string[] strings) cil managed
  {
    .param [1]
    .custom instance void [mscorlib]System.ParamArrayAttribute::.ctor() = ( 01 00 00 00 ) // Code size       17 (0x11)
    .maxstack  2
    .locals init ([0] string CS$1$0000)
    IL_0000:  nop
    IL_0001:  ldstr      "{0}{1}{2}"
    IL_0006:  ldarg.0
    IL_0007:  call       string [mscorlib]System.String::Format(string,  object[])
    IL_000c:  stloc.0
    IL_000d:  br.s       IL_000f
    IL_000f:  ldloc.0
    IL_0010:  ret
  } // end of method Program::Format

String.Format (my favorite of all the methods), comes in at a code size of 17 lines. The additional space is required for the string's template, which of course isn't necessary with String.Concat, but allows you to perform a number of useful operations on a string. For instance, String.Concat will only string the strings together. If you want to add a space between them, you'd have to create either one string to represent a space and concat that along (which gives you the same amount of code as String.Format anyway), or you could do something like:

string overDoingIt = String.Concat(string[0], " probably", string[1], " big fat", string[2]);

Not to mention, String.Format allows you to easily apply formatting rules without individually creating new objects. Granted, it would be converted into IL as something using a number formatter, but it makes our jobs as developers much easier.

Pluses

  .method private hidebysig static string
          Pluses(string[] strings) cil managed
  {
    .param [1]
    .custom instance void [mscorlib]System.ParamArrayAttribute::.ctor() = ( 01 00 00 00 ) // Code size       20 (0x14)
    .maxstack  4
    .locals init ([0] string CS$1$0000)
    IL_0000:  nop
    IL_0001:  ldarg.0
    IL_0002:  ldc.i4.0
    IL_0003:  ldelem.ref
    IL_0004:  ldarg.0
    IL_0005:  ldc.i4.1
    IL_0006:  ldelem.ref
    IL_0007:  ldarg.0
    IL_0008:  ldc.i4.2
    IL_0009:  ldelem.ref
    IL_000a:  call       string [mscorlib]System.String::Concat(string, string, string)
    IL_000f:  stloc.0
    IL_0010:  br.s       IL_0012
    IL_0012:  ldloc.0
    IL_0013:  ret
  } // end of method Program::Pluses

I see the (+) operator used a lot for string concatenation. There have been a number of articles that claim this performance is worse than that of String.Concat. Not even bothering with the actual performance aspect of it, you can see that this requires nearly twice as much intermediate language code to be generated than String.Concat.

If you're writing an application that requires thousands of string concatenation operations, I'd suggest using String.Concat. Even if you have to hard-code single characters as constants and occasionally pass a new string into the mix, it should still offer a great deal less generated code (and presumably better performance) than the (+) operator.

Builder

  .method private hidebysig static string
          Builder(string[] strings) cil managed
  {
    .param [1]
    .custom instance void [mscorlib]System.ParamArrayAttribute::.ctor() = ( 01 00 00 00 )    // Code size       48 (0x30)
    .maxstack  3
    .locals init ([0] class [mscorlib]System.Text.StringBuilder sb, [1] string CS$1$0000)
    IL_0000:  nop
    IL_0001:  newobj     instance void [mscorlib]System.Text.StringBuilder::.ctor()
    IL_0006:  stloc.0
    IL_0007:  ldloc.0
    IL_0008:  ldarg.0
    IL_0009:  ldc.i4.0
    IL_000a:  ldelem.ref
    IL_000b:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
    IL_0010:  pop
    IL_0011:  ldloc.0
    IL_0012:  ldarg.0
    IL_0013:  ldc.i4.1
    IL_0014:  ldelem.ref
    IL_0015:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
    IL_001a:  pop
    IL_001b:  ldloc.0
    IL_001c:  ldarg.0
    IL_001d:  ldc.i4.2
    IL_001e:  ldelem.ref
    IL_001f:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
    IL_0024:  pop
    IL_0025:  ldloc.0
    IL_0026:  callvirt   instance string [mscorlib]System.Object::ToString()
    IL_002b:  stloc.1
    IL_002c:  br.s       IL_002e
    IL_002e:  ldloc.1
    IL_002f:  ret
  } // end of method Program::Builder

I see this used a lot in ASP.NET for injecting startup JavaScript scripts (even for 5 lines of code!). Aside from the obvious problems with that, I'd like to mention that in .NET 3.0 and higher, Page.ClientScript.RegisterStartupScript now has an overload which adds script tags. That means you don't have to worry about the curly braces that would otherwise mess up your String.Format.

Anyway, what's going on here is: in lines 15, 21, and 27, we're calling the method Append on our instance of StringBuilder (instantiated as 'sb' in line 7). The strings are popped off the stack and passed into the method. At the end, we still have to call ToString() on our object. This is obviously way more work than is necessary. Granted, there are times when StringBuilder comes in handy, but simple concatenation really shouldn't use it.

Joiner

  .method private hidebysig static string
          Joiner(string[] strings) cil managed
  {
    .param [1]
    .custom instance void [mscorlib]System.ParamArrayAttribute::.ctor() = ( 01 00 00 00 )  // Code size       17 (0x11)
    .maxstack  2
    .locals init ([0] string CS$1$0000)
    IL_0000:  nop
    IL_0001:  ldstr      ""
    IL_0006:  ldarg.0
    IL_0007:  call       string [mscorlib]System.String::Join(string, string[])
    IL_000c:  stloc.0
    IL_000d:  br.s       IL_000f
    IL_000f:  ldloc.0
    IL_0010:  ret
  } // end of method Program::Joiner

String.Join is interesting in that it's sort of between String.Concat and String.Format. I usually overlook String.Join because, like I said, I prefer String.Format. But, look at how the Joiner method requires the same amount of IL code to be generated as String.Format. There really isn't any additional formatting required here, so String.Join is probably the second best solution.

Assume for a second that we didn't have any spacing in our strings, and instead had "The", "cake", "is", "a", "lie". Instead of passing these to String.Concat with a space such as:

string space = " ";
// typing the following line gets boring very quickly:
return String.Concat(string[0], space, string[1], space, string[2], space // etc...

we could use String.Join:

return String.Join(" ", strings));

Conclusion
Here is a quick summary of the findings of this little exploration:

  • String.Concat-- Good for joining strings without any additional processing
  • String.Join-- Good for joining strings with a specified delimeter
  • String.Format-- Same amount of code for String.Join, but allows for additional formatting of strings
  • String (+) operator-- Unnecessary amount of overhead when used to simply combine supplied strings
  • StringBuilder-- Overly bloated method for simple concatenation.
20Mar/10

Programming to Interfaces or Objects?

The other day, I was asked to add some functionality to code that regularly instantiates objects as interfaces, and I was wondering what exactly is the point? I understand the polymorphic aspect of interfaces, and I fully agree that interfaces should be used as parameter and return types. But, is there some sort of performance gain when implementing an object as the interface rather than the object?

To test this question, I'm going to run a simple console application to list two actors and 2 or 3 movies for each one.
Here is the code required to run the application:


    class Actor
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public decimal AnnualSalary { get; set; }
        public List<Movie> Roles { get; set; }
        public override string ToString()
        {
            return String.Format("{0}({1}), {2:c}/year",
                Name, Age, AnnualSalary);
        }
    }

    class Movie
    {
        public string Title { get; set; }
        public int ReleaseYear { get; set; }
        public string Director { get; set; }
        public decimal Budget { get; set; }

        public override string ToString()
        {
            return String.Format("{0}({1}), {2} [{3:c}]",
                Title, ReleaseYear, Director, Budget);
        }
    }

    class MockRepository
    {
         internal List<Actor> GetActors()
        {
            List<Actor> actors = new List<Actor>();
            actors.AddRange(new List<Actor>
            {
                new Actor { Name = "Zooey Deschanel",
                    Age = Convert.ToInt32(
                        DateTime.Now.Subtract(
                            new DateTime(1980, 1, 17)
                        ).TotalDays) / 365,
                    AnnualSalary = 1000000,
                    Roles = GetMovies("Zooey")
                },
                new Actor {
                    Name = "Tony Jaa",
                    Age = Convert.ToInt32(
                     DateTime.Now.Subtract(
                        new DateTime(1976, 2, 5)
                    ).TotalDays) / 365,
                   AnnualSalary = 5000000,
                   Roles = GetMovies("Tony")
                }
            });
            return actors;
        }

        internal List<Movie> GetMovies(string actor)
        {
            List<Movie> movies = new List<Movie>();
            switch (actor)
            {
                case "Zooey":
                    movies.Add(new Movie
                    {
                        Director = "Michael Clancy",
                        Title = "Eulogy",
                        ReleaseYear = 2004,
                        Budget = 10000000
                    });
                    movies.Add(new Movie
                    {
                        Title = "(500) Days of Summer",
                        Director = "Marc Webb",
                        ReleaseYear = 2009,
                        Budget = 7500000
                    });
                    movies.Add(new Movie
                    {
                        Title = "Yes Man",
                        Director = "Peyton Reed",
                        ReleaseYear = 2008,
                        Budget = 50000000
                    });
                    break;
                case "Tony":
                    movies.Add(new Movie
                    {
                        Title = "Ong Bak 2",
                        Director = "Panna Rittikrai",
                        ReleaseYear = 2008,
                        Budget = 50000000
                    });
                    movies.Add(new Movie
                    {
                        Title = "Ong Bak",
                        Director = "Prachya Pinkaew",
                        ReleaseYear = 2003,
                        Budget = 50000000
                    });
                    break;
                default:
                    break;
            }

            return movies;
        }
    }

And, here is the console application:

        static void Main(string[] args)
        {
            MockRepository repository = new MockRepository();
            List<Actor> actors = repository.GetActors();

            foreach (Actor actor in actors)
            {
                Console.WriteLine(actor.ToString());
                foreach (Movie movie in actor.Roles)
                {
                    Console.WriteLine("\t{0}", movie.ToString());
                }
            }

            Console.ReadLine();
        }

This produces the following output (salaries and annual budgets aren't correct):

Zooey Deschanel(30), $1,000,000.00/year
        Eulogy(2004), Michael Clancy [$10,000,000.00]
        (500) Days of Summer(2009), Marc Webb [$7,500,000.00]
        Yes Man(2008), Peyton Reed [$50,000,000.00]
Tony Jaa(34), $5,000,000.00/year
        Ong Bak 2(2008), Panna Rittikrai [$50,000,000.00]
        Ong Bak(2003), Prachya Pinkaew [$50,000,000.00]

I've gone back and modified the above code to return interfaces instead of objects.

// Note: IList does not implement AddRange. So instead of:
IList<IActor> actors = new List<IActor>();
actors.AddRange(new List<IActor> { /* etc */ } );
// We'll have to do:
List<IActor> actors = new List<IActor>();
actors.AddRange(new List<IActor> { /* etc */ });

For *fun* I've outputted the Intermediate Language for each console application and run a diff between the two. The code follows, but it is easily summed up as: the code is relatively the same.

41c41
< // MVID: {D457D4D6-EFDE-4F7F-9A7D-F77E2FB92D1F}
---
> // MVID: {EF8FAF3C-306F-4E76-AE54-3A4CA179FAB7}
47c47
< // Image base: 0x00400000
---
> // Image base: 0x003E0000
61,65c61,65
<              [1] class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IActor> actors,
<              [2] class InterfacesOrObjects.IActor actor,
<              [3] class InterfacesOrObjects.IMovie movie,
<              [4] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class InterfacesOrObjects.IActor> CS$5$0000,
<              [5] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class InterfacesOrObjects.IMovie> CS$5$0001,
---
>              [1] class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Actor> actors,
>              [2] class InterfacesOrObjects.Actor actor,
>              [3] class InterfacesOrObjects.Movie movie,
>              [4] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class InterfacesOrObjects.Actor> CS$5$0000,
>              [5] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class InterfacesOrObjects.Movie> CS$5$0001,
71c71
<     IL_0008:  callvirt   instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IActor> InterfacesOrObjects.MockRepository::GetActors()
---
>     IL_0008:  callvirt   instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Actor> InterfacesOrObjects.MockRepository::GetActors()
75c75
<     IL_0010:  callvirt   instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IActor>::GetEnumerator()
---
>     IL_0010:  callvirt   instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Actor>::GetEnumerator()
82c82
<       IL_001b:  call       instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class InterfacesOrObjects.IActor>::get_Current()
---
>       IL_001b:  call       instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class InterfacesOrObjects.Actor>::get_Current()
86c86
<       IL_0023:  callvirt   instance string InterfacesOrObjects.IActor::ToString()
---
>       IL_0023:  callvirt   instance string [mscorlib]System.Object::ToString()
91,92c91,92
<       IL_0030:  callvirt   instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie> InterfacesOrObjects.IActor::get_Roles()
<       IL_0035:  callvirt   instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie>::GetEnumerator()
---
>       IL_0030:  callvirt   instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie> InterfacesOrObjects.Actor::get_Roles()
>       IL_0035:  callvirt   instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie>::GetEnumerator()
99c99
<         IL_0040:  call       instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class InterfacesOrObjects.IMovie>::get_Current()
---
>         IL_0040:  call       instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class InterfacesOrObjects.Movie>::get_Current()
104c104
<         IL_004d:  callvirt   instance string InterfacesOrObjects.IMovie::ToString()
---
>         IL_004d:  callvirt   instance string [mscorlib]System.Object::ToString()
110c110
<         IL_005b:  call       instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class InterfacesOrObjects.IMovie>::MoveNext()
---
>         IL_005b:  call       instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class InterfacesOrObjects.Movie>::MoveNext()
121c121
<         IL_006a:  constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class InterfacesOrObjects.IMovie>
---
>         IL_006a:  constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class InterfacesOrObjects.Movie>
129c129
<       IL_007b:  call       instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class InterfacesOrObjects.IActor>::MoveNext()
---
>       IL_007b:  call       instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class InterfacesOrObjects.Actor>::MoveNext()
140c140
<       IL_008a:  constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class InterfacesOrObjects.IActor>
---
>       IL_008a:  constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class InterfacesOrObjects.Actor>
197c197
<           instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie>
---
>           instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie>
203c203
<           instance void  set_Roles(class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie> 'value') cil managed
---
>           instance void  set_Roles(class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie> 'value') cil managed
228c228
<   .property instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie>
---
>   .property instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie>
231,232c231,232
<     .get instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie> InterfacesOrObjects.IActor::get_Roles()
<     .set instance void InterfacesOrObjects.IActor::set_Roles(class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie>)
---
>     .get instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie> InterfacesOrObjects.IActor::get_Roles()
>     .set instance void InterfacesOrObjects.IActor::set_Roles(class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie>)
246c246
<   .field private class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie> '<Roles>k__BackingField'
---
>   .field private class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie> '<Roles>k__BackingField'
334c334
<           instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie>
---
>           instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie>
340c340
<     .locals init (class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie> V_0)
---
>     .locals init (class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie> V_0)
342c342
<     IL_0001:  ldfld      class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie> InterfacesOrObjects.Actor::'<Roles>k__BackingField'
---
>     IL_0001:  ldfld      class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie> InterfacesOrObjects.Actor::'<Roles>k__BackingField'
351c351
<           instance void  set_Roles(class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie> 'value') cil managed
---
>           instance void  set_Roles(class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie> 'value') cil managed
358c358
<     IL_0002:  stfld      class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie> InterfacesOrObjects.Actor::'<Roles>k__BackingField'
---
>     IL_0002:  stfld      class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie> InterfacesOrObjects.Actor::'<Roles>k__BackingField'
415c415
<   .property instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie>
---
>   .property instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie>
418,419c418,419
<     .set instance void InterfacesOrObjects.Actor::set_Roles(class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie>)
<     .get instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie> InterfacesOrObjects.Actor::get_Roles()
---
>     .set instance void InterfacesOrObjects.Actor::set_Roles(class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie>)
>     .get instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie> InterfacesOrObjects.Actor::get_Roles()
699c699
<   .method assembly hidebysig instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IActor>
---
>   .method assembly hidebysig instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Actor>
704,705c704,705
<     .locals init ([0] class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IActor> actors,
<              [1] class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IActor> '<>g__initLocal0',
---
>     .locals init ([0] class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Actor> actors,
>              [1] class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Actor> '<>g__initLocal0',
708c708
<              [4] class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IActor> CS$1$0000,
---
>              [4] class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Actor> CS$1$0000,
712c712
<     IL_0001:  newobj     instance void class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IActor>::.ctor()
---
>     IL_0001:  newobj     instance void class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Actor>::.ctor()
715c715
<     IL_0008:  newobj     instance void class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IActor>::.ctor()
---
>     IL_0008:  newobj     instance void class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Actor>::.ctor()
751,752c751,752
<     IL_006f:  call       instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie> InterfacesOrObjects.MockRepository::GetMovies(string)
<     IL_0074:  callvirt   instance void InterfacesOrObjects.Actor::set_Roles(class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie>)
---
>     IL_006f:  call       instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie> InterfacesOrObjects.MockRepository::GetMovies(string)
>     IL_0074:  callvirt   instance void InterfacesOrObjects.Actor::set_Roles(class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie>)
755c755
<     IL_007b:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IActor>::Add(!0)
---
>     IL_007b:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Actor>::Add(!0)
791,792c791,792
<     IL_00e1:  call       instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie> InterfacesOrObjects.MockRepository::GetMovies(string)
<     IL_00e6:  callvirt   instance void InterfacesOrObjects.Actor::set_Roles(class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie>)
---
>     IL_00e1:  call       instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie> InterfacesOrObjects.MockRepository::GetMovies(string)
>     IL_00e6:  callvirt   instance void InterfacesOrObjects.Actor::set_Roles(class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie>)
795c795
<     IL_00ed:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IActor>::Add(!0)
---
>     IL_00ed:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Actor>::Add(!0)
798c798
<     IL_00f4:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IActor>::AddRange(class [mscorlib]System.Collections.Generic.IEnumerable`1<!0>)
---
>     IL_00f4:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Actor>::AddRange(class [mscorlib]System.Collections.Generic.IEnumerable`1<!0>)
808c808
<   .method assembly hidebysig instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie>
---
>   .method assembly hidebysig instance class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie>
813c813
<     .locals init ([0] class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie> movies,
---
>     .locals init ([0] class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie> movies,
819c819
<              [6] class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie> CS$1$0000,
---
>              [6] class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie> CS$1$0000,
822c822
<     IL_0001:  newobj     instance void class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie>::.ctor()
---
>     IL_0001:  newobj     instance void class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie>::.ctor()
864c864
<     IL_0072:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie>::Add(!0)
---
>     IL_0072:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie>::Add(!0)
887c887
<     IL_00b5:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie>::Add(!0)
---
>     IL_00b5:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie>::Add(!0)
910c910
<     IL_00f8:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie>::Add(!0)
---
>     IL_00f8:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie>::Add(!0)
935c935
<     IL_0146:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie>::Add(!0)
---
>     IL_0146:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie>::Add(!0)
958c958
<     IL_018f:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.IMovie>::Add(!0)
---
>     IL_018f:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<class InterfacesOrObjects.Movie>::Add(!0)
988c988
< // WARNING: Created Win32 resource file C:\Users\Jim\Desktop\Interfaces or Objects\AsInterfaces.res
---
> // WARNING: Created Win32 resource file C:\Users\Jim\Desktop\Interfaces or Objects\AsObjects.res

This leads me to the question, why would anyone program implementations as interfaces? In Visual Studio, when you right click and choose "Go to declaration" on a method implemented as an interface instead of an object (for instance, if actor.Roles used a getter to perform some action on movies), you will be directed to the interface, not to the actual method of the object. As noted above, IList doesn't implement AddRange, so we'd have to explicitly cast the interface implementation in order to use the desired method.

Is it possible that interfaces can be overdone?

I don't think there is any huge benefit to using interfaces unless your application is going to be "interfaced" with, or if there is some amount of inheritance or polymorphism in the application. In the example posted above, the interfaces are completely unnecessary.

1Mar/10

log4net configuration in .NET 3.5

Step 1 Add Reference
Right click on the "References" folder and choose add reference. Browse to the location of log4net and add it to the project.

Step 2 Add Config Section Reference
In web.config, add a reference to the log4net config section handler. This will look like:

<?xml version="1.0"?>
<configuration>
 <configSections>
  <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/>
 <!-- other sections/sectionGroups -->
 </configSections>
</configuration>

Step 3 Add the log4net configuration Section
All that is left is to add the actual configuration. There are an unlimited number of ways this can be done, with numerous different logs and log types. An example configuration follows. This configuration creates a log for NHibernate with a max size of 8MB, a rolling file (max size 3MB), and a a console log. Anything logged to the logger named NHibernate.SQL will record only if they are ERROR level or higher. Anything logged without specifying a logger name is logged to root, and only goes to the console and rolling file.

 <log4net>
  <appender name="NHibernateFileLog" type="log4net.Appender.RollingFileAppender,log4net">
   <file value="logs/nhibernate.txt"/>
   <appendToFile value="true"/>
   <rollingStyle value="Size"/>
   <maxSizeRollBackups value="0"/>
   <maximumFileSize value="8MB"/>
   <staticLogFileName value="true"/>
   <layout type="log4net.Layout.PatternLayout,log4net">
    <conversionPattern value="%d [%t] %-5p %c - %m%n"/>
   </layout>
  </appender>
  <appender name="console" type="log4net.Appender.ConsoleAppender, log4net">
   <layout type="log4net.Layout.PatternLayout,log4net">
    <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p %c{1}:%L - %m%n"/>
   </layout>
  </appender>
    <!-- log4net uses 5 levels, namely DEBUG, INFO, WARN, ERROR and FATAL. -->
  <appender name="rollingFile" type="log4net.Appender.RollingFileAppender,log4net">
   <param name="File" value="logs/RollingLog.txt"/>
   <param name="AppendToFile" value="false"/>
   <param name="RollingStyle" value="Date"/>
   <param name="DatePattern" value="yyyy.MM.dd"/>
   <param name="StaticLogFileName" value="true"/>
   <maximumFileSize value="3MB"/>
   <maxSizeRollBackups value="0"/>
   <staticLogFileName value="true"/>
   <layout type="log4net.Layout.PatternLayout,log4net">
    <param name="ConversionPattern" value="%d{HH:mm:ss.fff} [%t] %-5p %c - %m%n"/>
   </layout>
  </appender>
  <logger name="NHibernate.SQL" additivity="false">
   <level value="ERROR"/>
   <appender-ref ref="NHibernateFileLog"/>
   <appender-ref ref="console"/>
   <appender-ref ref="rollingFile"/>
  </logger>
  <root>
   <level value="ERROR"/>
   <appender-ref ref="console"/>
      <appender-ref ref="rollingFile"/>
   <!--Uncomment the following appender for verbose output (degrades performance)-->
   <!--<appender-ref ref="rollingFile"/>-->
  </root>
 </log4net>
 

Step 4
Now, all that's left is to call log4net's configure method before any other (read: **error prone**) code is called.
For example, in an ASP.NET Web application, you could add this to Global.asax:

public class GlobalAsax : HttpApplication
{
    void Application_Start(object sender, EventArgs e)
    {
        log4net.Config.XmlConfigurator.Configure();
    }
}

Other logging options include database, mail, net, access.

For more information and examples on log4net, visit http://logging.apache.org/log4net/release/config-examples.html

An example Logger implementation in C#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using log4net;
using log4net.Config;
namespace ETeacherWeb.Common
{
    /// <summary>
    /// Logger class for log4net programmatic logging
    /// </summary>
    public static class Logger
    {
        /// <summary>
        /// Severity/Level of the log entry
        /// </summary>
        public enum LogLevel
        {
            DEBUG = 1,
            ERROR,
            FATAL,
            INFO,
            WARN
        }
        #region Members
        private static readonly ILog logger = LogManager.GetLogger(typeof(Logger));
        #endregion
        #region Constructors
        static Logger()
        {
            XmlConfigurator.Configure();
        }
        #endregion
        #region Methods
        /// <summary>
        /// Write a string to the log with a specified level of severity
        /// </summary>
        /// <param name="logLevel">The severity of the log entry</param>
        /// <param name="log">The log entry</param>
        public static void WriteLog(LogLevel logLevel, String log)
        {
            if (logLevel.Equals(LogLevel.DEBUG))
            {
                logger.Debug(log);
            }
            else if (logLevel.Equals(LogLevel.ERROR))
            {
                logger.Error(log);
            }
            else if (logLevel.Equals(LogLevel.FATAL))
            {
                logger.Fatal(log);
            }
            else if (logLevel.Equals(LogLevel.INFO))
            {
                logger.Info(log);
            }
            else if (logLevel.Equals(LogLevel.WARN))
            {
                logger.Warn(log);
            }
        }
        #endregion
    }
}

To use the above code, you would call

 Logger.WriteLog(LogLevel.DEBUG, "The expected logic failed validation");
19Feb/10

Basics: Posting data to a remote server via .NET

Class for Remote Posting:

    public class RemotePost
        {
            #region Fields and Properties
            private string _url;
            private string _postData;
            private byte[] _data;

            /// <summary>
            /// URL to which the Post is sent
            /// </summary>
            public string Url
            {
                get
                {
                    if (!_url.StartsWith("http://"))
                        return String.Format("{0}{1}", "http://", _url);
                    else
                        return _url;
                }
                set
                {
                    _url = value;
                }
            }

            /// <summary>
            /// The Method to Use. Can also change to "GET"
            /// </summary>
            private string Method
            {
                get
                {
                    return "POST";
                }
            }

            /// <summary>
            /// A string of data you want to post to a URL
            /// </summary>
            public string PostData
            {
                get
                {
                    return _postData;
                }
                set
                {
                    _postData = value;
                }
            }

            /// <summary>
            /// Pulls the string of PostData
            /// </summary>
            public byte[] Data
            {
                get
                {
                    if (_data != null)
                        return _data;
                    else
                        return ASCIIEncoding.Default.GetBytes(PostData);
                }
                set
                {
                    _data = value;
                }
            }
            #endregion

            /// <summary>
            /// Posts to remote URL, and returns the response
            /// </summary>
            /// <returns></returns>
            public string Post()
            {
                if (string.IsNullOrEmpty(Url) | string.IsNullOrEmpty(PostData))
                    return "Error with URL or Post Data, try again";

                HttpWebRequest req =
                    (HttpWebRequest)WebRequest.Create(Url);
                req.Method = Method;
                req.ContentType = "application/x-www-form-urlencoded";
                req.ContentLength = Data.Length;
                Stream newStream = req.GetRequestStream();

                // send!
                newStream.Write(Data, 0, Data.Length);
                newStream.Close();

                HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
                Encoding enc = System.Text.Encoding.GetEncoding(1252);

                StreamReader reader =
                    new StreamReader(resp.GetResponseStream(), enc);

                string response = reader.ReadToEnd();
                return response;
            }
        }

Usage:

    RemotePost app2 = new RemotePost();
    app2.PostData = "var1=encodeme&var2=encodemetoo";
    app2.Url = "http://www.example.com/ProcessingPage.aspx";
    txtServerResponse.Text = app2.Post();

The comments and code are pretty self-explanatory. Have fun!

Tagged as: , No Comments
15Feb/10

Explaining advanced features of C# 3.0

C# 3.0 Func delegates and Expressions

In this post, I'll attempt to clarify the meaning of Func delegates and Expressions.
These are very useful additions to C# 3.0, but it seems to be rarely blogged about.

// Note: I assume you have a general understanding of delegates and anonymous methods

Microsoft's definitions:

Func

// Encapsulates a method that has no parameters and returns
// a value of the type specified by the TResult parameter.
public delegate TResult Func<TResult>()
public delegate TResult Func<TParam0, TResult>(TParam0 arg0)
public delegate TResult Func<TParam0, TParam1, TResult>(TParam0 arg0, TParam1 arg1)
// etc. up to 3 Generic Input parameters and a Generic Result parameter

Expression

// Represents a strongly typed lambda expression as a data structure
// in the form of an expression tree. This class cannot be inherited.
public sealed class Expression<TDelegate> : LambdaExpression

// Describes a lambda expression.
public class LambdaExpression : Expression

// Provides the base class from which the classes that represent expression
// tree nodes are derived. It also contains static (Shared in Visual Basic)
// factory methods to create the various node types. This is an abstract class.
public abstract class Expression
// NOTE : Expression<TDelegate> is not an override of Expression, they are completely independent classes 

Quick Rundown

Func<TResult>

The Func delegates are simply Generic delegates introduced to make our lives easier. You specify your return type, or the types of your input parameters and your return type.

For instance, assume you have an object called Product, with a method whose signature is:

public bool AddComponent(Component c) { /* logic */ }

You could use the Func delegate in a number of ways on the product object:

// our objects
Product product = new Product();

// Examples
Func<bool> addComponent1 = product.AddComponent( new Component() );
Func<bool> addComponent2 = delegate() { return  product.AddComponent( new Component() ); };
Func<bool> addComponent3 = () => product.AddComponent( new Component() );

if(addComponent1()) { /* Do stuff */ }
if(addComponent2()) { /* Do stuff */ }
if(addComponent3()) { /* Do stuff */ }

The above example is the common explanation of Func delegates. However, to a beginner, this may seem like a ridiculous way to rename a method. The point being, it can be difficult to understand why you'd generalize

product.AddComponent( new Component() );

as 'addComponent1' when you could just as easily write out

if(product.AddComponent( new Component() ) ) { /* Do stuff */ } 

Another, more useful example of a real-world application:

Product product = new Product();
Func<bool> addAllProducts = () =>
    {
    if (product.AddComponent(new Component { Name = "Component1" })
        && product.AddComponent(new Component { Name = "Component2" })
        && product.AddComponent(new Component { Name = "Component3" }))
        { return true; }
        else { return false; }
    };

bool wasSuccessful = addAllProducts(); // wasSuccessful is true if AddComponent succeeds every time.
// NOTE: Here, I've used object instantiation for the Component object, this is another feature of C# 3.0

Expression<TDelegate>

Of particular note is the difference between Func<TResult> and Expression<TDelegate>. A Func<TResult> is code (a delegate) that is compiled at runtime, while an Expression<TDelegate> is a data representation (as an Expression Tree) of that delegate. This means you can act upon any part of an Expression<TDelegate> as if it were a data structure (similar to getting a count of objects in a list or accessing a dictionary value via dictionary key).

You've probably read that paragraph and said "...what?" If so, I don't blame you.
Take, for instance, the example given at MSDN:

System.Linq.Expressions.Expression<Func<int, bool>> expr = (i) => i < 5;

This doesn't give us much to go by. However, when you think about expr as a data structure, you're basically instantiating this data structure with 'i => i < 5;'. Now, you can pass this expression tree around your application and you're free to access any part of the expression tree as if it is its own separate entity; you can't do this with a delegate alone. A fairly good example is available at MSDN.

To better clarify, let's look at the parts of this expression tree:

    Expression
  • Parameter
  • Body
    • --Operation
    • --Constant
/* Expression */ (i) => i < 5;
/* Parameter */  (i)
/* Body */  i < 5;
/* Operation NodeType */ <
/* Constant */ 5

I know breaking it down into these parts seems very simplistic, but the point is that you can't do this with a delegate. If you passed a delegate to a method, that's it. You can't figure out what the first parameter was declared as, or the operation being performed (less than, greater than, etc). You'd have no way of finding what constant was supplied.

To compile the above Expression tree, you could do the following:

bool oneIsLess = expr.Compile()(1); /* result: true */

Why is this important? You can easily access the parts of the expression as described by the MSDN article:

Expression<Func<int, bool>> exprTree = num => num < 5;

ParameterExpression param = (ParameterExpression)exprTree.Parameters[0];
BinaryExpression operation = (BinaryExpression)exprTree.Body;
ParameterExpression left = (ParameterExpression)operation.Left;
ConstantExpression right = (ConstantExpression)operation.Right;

Console.WriteLine("Decomposed expression: {0} => {1} {2} {3}",
                  param.Name, left.Name, operation.NodeType, right.Value);

// This code produces the following output:
//  Decomposed expression: num => num LessThan 5

Using the Expression Tree Visitor from MSDN, you can access the parts of a number of Expression Trees.

Practical Applications

Because this post is already very long, instead of going in-depth into practical applications now, I'll save that for a future post.

Instead, I'd like to direct you to the project and usage of Expression trees that made me delve further into the topic: Fluent NHibernate. I had previously thought that Expression Trees and Lamda Expressions were geared more toward LINQ providers and less important for daily development. However, if you were to download the source for Fluent NHibernate, you'd see another cool usage of Expression Trees: static reflection.

James Gregory, the principal developer of Fluent NHibernate wrote a nice introduction to static reflection, in which he illustrates the following usage:

/* Copyright James Gregory, Creative Commons:Attribution-Non-Commercial-Share Alike 2.0 UK: England & Wales */
public PropertyInfo GetProperty<TEntity>(Expression<Func<TEntity, object>> expression) { /* Do stuff */ }
GetProperty<Customer>(customer => customer.Name); // usage

As you can see, instead of retrieving the PropertyInfo of the Customer object's Name property by hard-coding a "Name" string, you're now free to refactor your code properly. In which case, if you were to change your 'Name' property, your tests or build process would fail, whereas the hard-coded string "Name" would be overlooked.

I encourage you to download the source code for Fluent NHibernate and take a look at how static reflection is being used.

Further Reading

http://www.lostechies.com/blogs/gabrielschenker/archive/2009/02/03/dynamic-reflection-versus-static-reflection.aspx
http://www.codeproject.com/Articles/36262/Getting-Fun-with-Net-Static-Reflection.aspx
http://ayende.com/Blog/archive/2005/10/29/StaticReflection.aspx
http://apobekiaris.blogspot.com/2009/06/more-static-reflection.html

Example Console Application

 static void Main(string[] args)
        {
            List<int> numbers = new List<int>();
            Random r = new Random();
            for (int i = 0; i < 15; i++)
            {
                numbers.Add(r.Next(0,50));
            }

            // Expression trees can be used to perform an action on objects
            Expression<Func<List<int>,int, bool>> isAvailable = (x,num) => x.Contains(num);
            for (int i = 0; i < 50; i++)
            {
                Console.WriteLine("Is {0} available? {1}", i, isAvailable.Compile()(numbers, i));
            }

            Product product = new Product();
            Func<bool> addAllProducts = () =>
            {
                if (product.AddComponent(new Component { Name = "Component1" })
                    && product.AddComponent(new Component { Name = "Component2" })
                    // && product.AddComponent(new Component { Name = "Component2" }) /* fails */
                    && product.AddComponent(new Component { Name = "Component3" }))
                { return true; }
                else { return false; }
            };

            bool wasSuccessful = addAllProducts();

            System.Linq.Expressions.Expression<Func<int, bool>> expr = i => i < 5;

            ParameterExpression param = (ParameterExpression)expr.Parameters[0];
            BinaryExpression operation = (BinaryExpression)expr.Body;
            ParameterExpression left = (ParameterExpression)operation.Left;
            ConstantExpression right = (ConstantExpression)operation.Right;

            Console.WriteLine("Decomposed expression: {0} => {1} {2} {3}",
                              param.Name, left.Name, operation.NodeType, right.Value);

        }
    }

    public class Product
    {
        public IList<Component> Components { get; private set; }
        public bool AddComponent(Component c)
        {
            if (Components.Contains(c))
                return false;
            else
            {
                Components.Add(c);
                return true;
            }
        }

        public Product()
        {
            Components = new List<Component>();
        }
    }

    public class Component
    {
        public string Name { get; set; }
        public override bool Equals(object obj)
        {
            if(!(obj is Component)) { return false; }
            return this.Name.Equals(((Component)obj).Name);
        }
    }