Thursday, November 6, 2008

The art of making the simple complex

I was going through our use of session variables in Asp.net today at work and found code very similar to the following on multiple places:

If Session("foo") Is Nothing Then
    Session.Add("foo", value)
Else
    Session.Remove("foo")
    Session.Add("foo", value)
End If

First off, if you thought you really had to use the "Add" method to set the value why not do the following:

If Not Session("foo") Is Nothing Then
    Session.Remove("foo")
End If 

Session.Add("foo", value)

Now, ofcourse, there's really no need to check if the value exists in the session before removing it since the "Remove" method throws no exception, so we'll just write:

Session.Remove("foo")
Session.Add("foo", value)

But ofcourse, any sensible developer would instead write:

Session("foo") = value

Saturday, October 18, 2008

Implementing interfaces in VB.Net

In this post I'll talk about VB's explicit interface implementation and how to best exploit the power this brings. I guess that it's a well known fact that interface implementation in VB is explicit but what does that mean really? It simply means that to implement an interface in a class the developer has to explicitly declare what members of the class implements the members of the interface. C# also has the ability to explicitly implement interfaces but it supports implicit interface implementation too which lets you implement an interface by declaring members with the same names and signatures as those of the interface. To implement the IDisposable interface implicitly we'd write the following:

public class Foo : IDisposable
{
    public void Dispose()
    {
        // Implementation here...
    }
}

The developer never tells the compiler that the method named "Dispose" implements the method "Dispose" of the IDisposable interface, the compiler figures this out by comparing the name and the signature of the method. To explicitly implement an interface in C# we'd write the following instead:

public class Foo : IDisposable
{
    void IDisposable.Dispose()
    {
        // Implementation here...
    }
}

In this implementation we explicitly say that the "Dispose" method implements the "Dispose" method of the interface IDisposable, note that there is no scope declared for this method, this is because it's only accessible through the interface. If you held an instance of the class "Foo" you would not be able to invoke the Dispose method without casting the instance to IDisposable.

Foo foo = new Foo();

foo.Dispose(); // will not compile
(foo as IDisposable).Dispose(); // will compile

As seen here this means that a method that implements an interface method must have the same name as the interface method and be public OR have no name at all and be private (explicit implementation). In VB on the other hand where implementation is always explicit we have a lot more freedom regarding naming and scope. For example a method implementing an interface method can have any scope (Private, Protected, Friend or Public) and also any name. Oh, well, any valid name that is.

Public Class Foo
    Implements IDisposable

    Public Sub ThisMethodIsNotNamedDispose() Implements IDisposable.Dispose
        ' Implementation here...
    End Sub

End Class

Now we have a public method called something completely different than "Dispose" but still implementing the "Dispose" method, if you were to cast an instance of the Foo class to the IDisposable interface and call the "Dispose" method on it the method "ThisMethodIsNotNamedDispose" would be invoked. As I said earlier an implementing method can have any scope, the method "ThisMethodIsNotNamedDispose" could just as well have been made private for example and we would end up with a situation very similar to the C# way of explicitly implementing interfaces. One very big difference though is that from within the class Foo you'd be able to call the method "ThisMethodIsNotNamedDispose" even though it's private, in C# however you can never call an explicit member implementation without casting to the interface, not even from within the implementing class itself.

Another cool thing about VB's explicit interface implementation is that a single method or property can implement methods or properties from multiple interfaces at the same time.

Public Class Foo
    Implements ICollection, ICountable

    '...

    Public ReadOnly Property Count() As Integer Implements ICollection.Count, ICountable.Count
        Get
            Return theCount
        End Get
    End Property

    '...

End Class

Public Interface ICountable
    ReadOnly Property Count() As Integer
End Interface

Interface implementation is one of the very few areas where I think VB outshines C# (XML-literals being the other area).

I think that hiding the methods of the interface in the public interface of the class (by explicitly implement the interface in C# and setting a non public scope in VB) is something that should be sparsely used. I use it only when a method makes no sense when the concrete type is known. For example if you create a LinkedList that implements the ICollection(T) interface there is really no need to ever call the "IsReadOnly" property when you know that you're holding a LinkedList that is never read only, this interface property should be hidden from the public interface of the class.

I've used the IDisposable interface as an example here but I would strongly advice against ever hiding the "Dispose" method of this interface in production code.

Field prefixes

The debate on whether to prefix private variables with a leading "_" or "m_" has engaged a lot of people lately since the public release of Style Cop which which enforces the "m_"-prefix (at least that's what I've been told, I haven't had a chance to try the application myself yet).

I think that prefixes are always bad, whether it's an "I" for interface, "C" for class or "m_" for member. I do appreciate the historic reasons for them but there is really no valid reason anymore, we have the "this" and "Me" keywords in C# and VB to differentiate between member variables and local variables or parameters. The only valid reason as I see it is to differentiate between a field and the property that expose that field.

public class Foo
{
    protected string _bar;

    public string Bar
    {
        get { return _bar; }
        set { _bar = value; }
    }
}

You might say that you could just use camelCasing for the field and PascalCasing for the property, but suppose that the class was to be inherited by VB.Net, "bar" would now be ambigous because VB is case insensitive thus the prefix has some validity. However since the introduction of automatic properties I see no reason for the prefix anymore. The only reason would have to do with performance (you could access the field direclty from inside the class rather than through the property) and I'd say that in most cases that's neglectible and I'd go with the increased maintainability the automatic properties gives you. Premature optimization is the root of all evil. Also in the example, if the backing field was just declared as private (as it should) there would be no issue.

Thursday, August 28, 2008

TDD - the jazz of development

I've come to think that test driven development is to development what jazz is to music. The main likeness is the improvisation part, in TDD you start out with a blank sheet so to speak, then you write tests, the tests are the actual improvisation part then you write code to satisfy that test, which is kind of like just playing along while another musician is improvising. To play improvised jazz you have to be a skilled musician, does this mean that to use TDD you'll have to be a skilled developer? I'm not sure...

Sunday, July 20, 2008

The "swallowtail"-pattern

Every now and then I use a pattern that I've myself named the "swallowtail"-pattern, this pattern is particularly useful in ECMA-script but it can be used in any language that has first class functions. The is useful when a function contains conditional logic that only has to be evaluated the first time it's invoked, for example an ECMA-script function might do different things depending on the browser that's hosting the script, let's look at an example.

Browser =
{
    setInnerText: function(element, text)
    {
        if (document.all)
        {
            element.innerText = text;
        }
        else
        {
            element.textContent = text;
        }
    }
}

The "Browser.setInnerText"-function checks whether the current browser is IE and in that case uses the "innerText"-property of the html-element, if it's another browser the "textContent"-property will be used. The problem is that the if-statement is evaluated every time the function is called, but once we know that we're running either browser we know what to do. To solve this we can exploit ECMA-scripts dynamic nature and the fact that it has fist class functions. Let's rewrite the function to the following.

Browser =
{
    setInnerText: function(element, text)
    {
        if (document.all)
        {
            Browser.setInnerText = function(e, t)
            {
                e.innerText = t;
            };
        }
        else
        {
            Browser.setInnerText = function(e, t)
            {
                e.textContent = t;
            };
        }
        
        Browser.setInnerText(element, text);
    }
}

Now once the if-statement is evaluated for the first time we create a new function that sets the inner text of the element using the correct property for the running browser, this new method has no conditional logic at all, it just sets the text. We point the "Browser.setInnerText"-function to this new function instead of the old one and then finally we call it with the passed in arguments. Now, the next time the "Browser.setInnerText"-function is called it's the new faster trimmed down method instead of the one with the if-statement.

As I said this pattern can be used in any language that supports first class function, it's however not a pattern that should be over used since the overhead in the particular language might be greater than the performance benefits.

Wednesday, June 11, 2008

ViewState extension methods

I created two extension methods for the StateBag type (ViewState) the other day and I find them quite handy so I thought I'd share them. They're for the very common task of accessing the values in the ViewState and are called GetValue and SetValue and makes my life a little easier.

Let's say we have two properties, the first is an integer called "Value" and the second a string called "Text", these would probably be implemented something like this (the differences in the implementations has to do with that the int is a value type and that string is a reference type):

public int Value
{
    get
    {
        int result = 0;

        if (this.ViewState["Value"] != null)
        {
            result = (int)this.ViewState["Value"];    
        }

        return result;
    }
    set
    {
        this.ViewState["Value"] = value;
    }
}

public string Text
{
    get
    {
        string result = (string)this.ViewState["Text"];
        return result != null ? result : string.Empty;
    }
    set
    {
        this.ViewState["Text"] = value;
    }
}

The extension methods I created let's us write this in a more straight forward way and we won't have to consider if the return type is a value type or a reference type.

public int Value
{
    get
    {
        return this.ViewState.GetValue("Value", 0);
    }
    set
    {
        this.ViewState.SetValue("Value", value, 0);
    }
}

public string Text
{
    get
    {
        return this.ViewState.GetValue("Text", string.Empty);
    }
    set
    {
        this.ViewState.SetValue("Text", value, string.Empty);
    }
}

Note that there's no need to cast the return value, this because the extension methods are generic methods and type inference is used. If the default value would be null you'd have to specify the type of the method like "this.ViewState.GetValue<string>("Text", null);" or "this.ViewState.GetValue("Text", (string)null);".

And here they are, the extension methods in all their glory!

/// <summary>
/// Gets a value from the view state collection.
/// </summary>
/// <typeparam name="T">The type of value to get.</typeparam>
/// <param name="viewState">The view state collection to get the value from.</param>
/// <param name="key">The key of the value in the view state.</param>
/// <param name="defaultValue">The default value of the view state field.</param>
/// <returns>The value from the view state.</returns>
public static T GetValue<T>(this StateBag viewState, string key, T defaultValue)
{
    object result = viewState[key];
    return result == null ? defaultValue : (T)result;
}

/// <summary>
/// Sets a value in the view state.
/// </summary>
/// <typeparam name="T">The type of value to set.</typeparam>
/// <param name="viewState">The view state collection to set the value in.</param>
/// <param name="key">The key of the value in the view state.</param>
/// <param name="defaultValue">The default value of the view state field.</param>
/// <param name="value">The value to set in the view state.</param>
public static void SetValue<T>(this StateBag viewState, string key, T value, T defaultValue)
{
    if (object.Equals(defaultValue, value))
    {
        viewState.Remove(key);
    }
    else
    {
        viewState[key] = value;
    }
}

That's all!

Saturday, May 17, 2008

For the last time

Every now and then I have to create a type converter (System.ComponentModel.TypeConverter), often to convert custom types to and from strings, there is some repetitive work involved in this. You have to override the CanConvertFrom- and CanConvertTo-methods and implement the conversion, now I've done this repetitive work for the last time since I created a class I call TypeConverterBase<TSource, TDestination> which implements all the logic save the conversion which it has two abstract methods for, it also has an abstract method IsValid for the destination type of the converter. It also provides some typed overloads for ConvertTo and ConvertFrom.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace Minimal
{
    /// <summary>
    /// Provides the base implementation for a type converter that converts between
    /// two types, only the abstract methods has to be implemented for a fully working
    /// type converter.
    /// </summary>
    /// <typeparam name="TSource">The source type of the converter.</typeparam>
    /// <typeparam name="TDestination">The destination type of the converter.</typeparam>
    public abstract class TypeConverterBase<tsource  , tdestination>
        : TypeConverter
    {
        #region Methods
        /// <summary>
        /// Gets whether the converter can convert from the source type to
        /// the type specified.
        /// </summary>
        /// <param name="context" />The context of the converter.</param>
        /// <param name="destinationType" />The type to check.</param>
        /// <returns>True if a conversion can be made.</returns>
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            if (destinationType.Equals(typeof(TDestination)))
            {
                return true;
            }

            return base.CanConvertTo(context, destinationType);
        }

        /// <summary>
        /// Gets whether the converter can convert to the source type of the converter to
        /// the type specified.
        /// </summary>
        /// <param name="context" />The context of the converter.</param>
        /// <param name="sourceType" />The type to check.</param>
        /// <returns>True if a conversion can be made.</returns>
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            if (sourceType.Equals(typeof(TDestination)))
            {
                return true;
            }

            return base.CanConvertFrom(context, sourceType);
        }

        /// <summary>
        /// Converts from the source type to the destination type.
        /// </summary>
        /// <param name="value" />The value to convert.</param>
        /// <returns>The converted value.</returns>
        public TDestination ConvertTo(TSource value)
        {
            return (TDestination)this.ConvertTo(value, typeof(TDestination));
        }

        /// <summary>
        /// Converts to the source type of the converter from the destination type.
        /// </summary>
        /// <param name="value" />The value to convert.</param>
        /// <returns>The converted value.</returns>
        public TSource ConvertFrom(TDestination value)
        {
            return (TSource)base.ConvertFrom(value);
        }

        ///<summary>
        /// Converts the given object to the type of this converter, using the specified
        /// context and culture information.
        /// </summary>
        /// <param name="context" />An System.ComponentModel.ITypeDescriptorContext that provides a format context.</param>
        /// <param name="culture" />The System.Globalization.CultureInfo to use as the current culture.</param>
        /// <param name="value" />The System.Object to convert.</param>
        /// <returns>An System.Object that represents the converted value.</returns>
        /// <exception cref="NotSupportedException">The conversion cannot be performed.</exception>
        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            if (value is TDestination)
            {
                return this.ConvertFrom(context, culture, (TDestination)value);
            }
            
            return base.ConvertFrom(context, culture, value);
        }

        /// <summary>
        /// Converts the given value object to the specified type, using the specified
        /// context and culture information.
        /// </summary>
        /// <param name="context" />An System.ComponentModel.ITypeDescriptorContext that provides a format context.</param>
        /// <param name="culture" />A System.Globalization.CultureInfo. If null is passed, the current culture
        /// is assumed.</param>
        /// <param name="value" />The value to convert.</param>
        /// <param name="destinationType" />The System.Type to convert the value parameter to.</param>
        /// <returns>An System.Object that represents the converted value.</returns>
        /// <exception cref="ArgumentNullException">System.ArgumentNullException: The destinationType parameter is null.</exception>
        /// <exception cref="NotSupportedException">The conversion cannot be performed.</exception>
        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType.Equals(typeof(TDestination)))
            {
                return this.ConvertTo(context, culture, (TSource)value);
            }

            return base.ConvertTo(context, culture, value, destinationType);
        }

        /// <summary>
        /// Returns whether the given value object is valid for this type and for the
        /// specified context.
        /// </summary>
        /// <param name="context" />An System.ComponentModel.ITypeDescriptorContext that provides a format context.</param>
        /// <param name="value" />The System.Object to test for validity.</param>
        /// <returns> true if the specified value is valid for this object; otherwise, false.</returns>
        public override bool IsValid(ITypeDescriptorContext context, object value)
        {
            if (value is TDestination)
            {
                return this.IsValid(context, (TDestination)value);
            }

            return base.IsValid(context, value);
        }

        protected abstract TSource ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, TDestination value);
        protected abstract TDestination ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, TSource value);
        protected abstract bool IsValid(ITypeDescriptorContext context, TDestination value);
        #endregion
    }
}

Monday, March 31, 2008

Dynamic lookup

A while back Charlie Calvert and Mads Torgersen wrote about dynamic lookup being part of the plans for C# 4.0. A code block specified with the "dynamic" key word will allow dynamic lookup with syntax like follows:

static void Main(string[] args)
{
    dynamic
    {
        object myDynamicObject = GetDynamicObject();
        myDynamicObject.SomeMethod();         // call a method   
        myDynamicObject.someString = "value"; // Set a field
        myDynamicObject[0] = 25;              // Access an indexer
    }
}

While this is a welcome feature I want it now! Of course I could resort to reflection but it gets tiresome writing all the code needed just to get a simple field or property so I made a little library that lets me write the previous example as follows:

static void Main(string[] args)
{
    object myDynamicObject = GetDynamicObject();
    myDynamicObject.Member("SomeMethod").Call();   // call a method   
    myDynamicObject.Member("someString").Set("value").Call(); // Set a field
    myDynamicObject.Member("Item")[0].Set(25).Call();  // Access an indexer
}

 

This also allows me to access private, protected or internal members of objects and on top of that it can compile functions for invoking the member on several instances of the same type.

I provide the code here but I'm sure there are several bugs in it so please don't use it in your applications as is. Actually please don't use it for anything like that without asking permission first...

#region Using Directives
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Globalization;
using System.Reflection.Emit;
#endregion

namespace Minimal.Reflection
{
    /// <summary>
    /// Gives dynamic access to object members.
    /// </summary>
    /// <typeparam name="TValue">The type of the return value, in the case of void
    /// object should be used.</typeparam>
    /// <typeparam name="TInstance">The kind of object that the call is performed on.</typeparam>
    public class MemberCall<TInstance, TValue>
    {
        #region Fields
        private object[] parameters;
        private Type[] signature;
        private TInstance instance;
        private string memberName;
        private bool setValueToMember;
        private MemberInfo member;
        private TValue setValue;
        private static readonly BindingFlags memberBindingFlags = 
            BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic;
        #endregion

        #region Constructor
        /// <summary>
        /// Creates a new instance.
        /// </summary>
        /// <param name="instance">The instance to invoke the member on.</param>
        /// <param name="name">The name of the member to invoke.</param>
        public MemberCall(TInstance instance, string name)
        {
            if (instance == null)
                throw new ArgumentNullException("instance");
            if (string.IsNullOrEmpty(name))
                throw new ArgumentNullException("name");

            this.instance = instance;
            this.memberName = name;
            this.signature = Type.EmptyTypes;
        } 
        #endregion

        #region Properties
        /// <summary>
        /// Sets the index parameter.
        /// </summary>
        /// <param name="index">The index parameter to use.</param>
        /// <returns></returns>
        public MemberCall<TInstance, TValue> this[object index]
        {
            get
            {
                this.parameters = new object[] { index };
                return this;
            }
        }
        #endregion

        #region Methods
        /// <summary>
        /// Specifies a value that's to be set to the member (field or property).
        /// </summary>
        /// <param name="value">The value to set to the member when invoked.</param>
        /// <returns>This MemberCall instance.</returns>
        public MemberCall<TInstance, T> Set<T>(T value) where T : TValue
        {
            if (typeof(T).Equals(typeof(TValue)))
            {
                this.setValue = value;
                this.setValueToMember = true;
                return (MemberCall<TInstance, T>)(object)this;
            }
            else
            {
                var result = new MemberCall<TInstance, T>(this.instance, this.memberName);
                result.parameters = this.parameters;
                result.signature = this.signature;
                result.setValue = value;
                result.setValueToMember = true;

                return result;
            }
        }

        /// <summary>
        /// The parameters of the call (method or property).
        /// </summary>
        /// <typeparam name="TValue">The type of the parameter.</typeparam>
        /// <param name="parameter">The value of the parameter.</param>
        /// <returns>This instance.</returns>
        public MemberCall<TInstance, TValue> Parameters<T1>(T1 parameter)
        {
            signature = new Type[] { typeof(T1) };
            parameters = new object[] { parameter };
            return this;
        }

        /// <summary>
        /// The parameters of the call (method or property).
        /// </summary>
        /// <typeparam name="T1">The type of the first parameter.</typeparam>
        /// <typeparam name="T2">The type of the second parameter.</typeparam>
        /// <param name="parameter1">The value of the first parameter.</param>
        /// <param name="parameter2">The value of the second parameter.</param>
        /// <returns>This instance.</returns>
        public MemberCall<TInstance, TValue> Parameters<T1, T2>(T1 parameter1, T2 parameter2)
        {
            this.signature = new Type[] { typeof(T1), typeof(T2) };
            this.parameters = new object[] { parameter1, parameter2 };
            return this;
        }

        /// <summary>
        /// The parameters of the call (method or property).
        /// </summary>
        /// <typeparam name="T1">The type of the first parameter.</typeparam>
        /// <typeparam name="T2">The type of the second parameter.</typeparam>
        /// <typeparam name="T3">The type of the third parameter.</typeparam>
        /// <param name="parameter1">The value of the first parameter.</param>
        /// <param name="parameter2">The value of the second parameter.</param>
        /// <param name="parameter3">The value of the third parameter.</param>
        /// <returns>This instance.</returns>
        public MemberCall<TInstance, TValue> Parameters<T1, T2, T3>(T1 parameter1, T2 parameter2, T3 parameter3)
        {
            this.signature = new Type[] { typeof(T1), typeof(T2), typeof(T3) };
            this.parameters = new object[] { parameter1, parameter2, parameter3 };
            return this;
        }

        /// <summary>
        /// The parameters of the call (method or property).
        /// </summary>
        /// <typeparam name="T1">The type of the first parameter.</typeparam>
        /// <typeparam name="T2">The type of the second parameter.</typeparam>
        /// <typeparam name="T3">The type of the third parameter.</typeparam>
        /// <typeparam name="T4">The type of the fourth parameter.</typeparam>
        /// <param name="parameter1">The value of the first parameter.</param>
        /// <param name="parameter2">The value of the second parameter.</param>
        /// <param name="parameter3">The value of the third parameter.</param>
        /// <param name="parameter3">The value of the fourth parameter.</param>
        /// <returns>This instance.</returns>
        public MemberCall<TInstance, TValue> Parameters<T1, T2, T3, T4>(T1 parameter1, T2 parameter2, T3 parameter3, T4 parameter4)
        {
            parameters = new object[] { parameter1, parameter2, parameter3, parameter4 };
            return this;
        }

        /// <summary>
        /// The parameters of the call (method or property).
        /// </summary>
        /// <typeparam name="T1">The type of the first parameter.</typeparam>
        /// <typeparam name="T2">The type of the second parameter.</typeparam>
        /// <typeparam name="T3">The type of the third parameter.</typeparam>
        /// <typeparam name="T4">The type of the fourth parameter.</typeparam>
        /// <param name="parameter1">The value of the first parameter.</param>
        /// <param name="parameter2">The value of the second parameter.</param>
        /// <param name="parameter3">The value of the third parameter.</param>
        /// <param name="parameter3">The value of the fourth parameter.</param>
        /// <param name="additionalParameters">In case that there are more than four parameters in the call,
        /// if any of these parameters are null (Nothing in VB) the signature of the member must be
        /// specified with a call to MemberCall{TValue}.Signature.</param>
        /// <returns>This instance.</returns>
        public MemberCall<TInstance, TValue> Parameters<T1, T2, T3, T4>(T1 parameter1, T2 parameter2, T3 parameter3, T4 parameter4, params object[] additionalParameters)
        {
            var l = new List<object>() { parameter1, parameter2, parameter3, parameter4 };
            l.AddRange(additionalParameters);
            parameters = l.ToArray();


            if (signature.Length != additionalParameters.Length + 4)
            {
                signature = new Type[additionalParameters.Length + 4];
            }

            signature[0] = typeof(T1);
            signature[1] = typeof(T2);
            signature[2] = typeof(T3);
            signature[3] = typeof(T4);

            for (int i = 4; i < parameters.Length; i++)
            {
                if (parameters[i] != null && signature[i] == null)
                {
                    signature[i] = parameters[i].GetType();
                }
            }

            return this;
        }

        /// <summary>
        /// Specifies the signature of the member, this is only needed if there are more than four 
        /// parameters in the call and one
        /// of the parameters after the fourth parameter is null (Nothing in VB).
        /// </summary>
        /// <param name="types">The <see cref="Type" />s (in the correct order) that makes up the signature of 
        /// the member that will be invoked, only needed if there are more than four parameters in the call and one
        /// of the parameters after the fourth parameter is null (Nothing in VB).</param>
        /// <returns>This MemberCall instance.</returns>
        public MemberCall<TInstance, TValue> Signature(params Type[] types)
        {
            signature = types;
            return this;
        }

        /// <summary>
        /// Invokes the member and returns the value that the call
        /// returns. Invoking methods that returns "void" (Sub in VB)
        /// return null.
        /// </summary>
        /// <returns>The result of the invokation.</returns>
        /// <exception cref="InvalidOperationException">The specified member was not found.</exception>
        public TValue Call()
        {
            var member = GetMember();

            switch (member.MemberType)
            {
                case MemberTypes.Field:
                    return InvokeField((FieldInfo)member);
                case MemberTypes.Method:
                    return InvokeMethod((MethodInfo)member);
                case MemberTypes.Property:
                    return InvokeProperty((PropertyInfo)member);
                default:
                    throw new NotSupportedException();
            }
        }

        private MemberInfo GetMember()
        {
            if (this.member == null)
            {
                var members = instance.GetType().GetMember(memberName, memberBindingFlags);

                if (members.Length == 1)
                {
                    this.member = members[0];
                }
                else if (members.Length > 0)
                {
                    this.member = this.ResolveMember(members);
                }
                else
                {
                    this.ThrowMemberNotFound();
                }
            }

            return this.member;
        }

        private void ThrowMemberNotFound()
        {
            throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
                "The member {0} was not found on the type {1}.", this.memberName, this.instance.GetType()));
        }

        private MemberInfo ResolveMember(MemberInfo[] members)
        {
            if (members[0].MemberType == MemberTypes.Property)
            {
                return this.ResolveProperty(members);
            }
            else
            {
                return this.ResolveMethod(members);
            }
        }

        private MemberInfo ResolveProperty(MemberInfo[] properties)
        {
            var result =
                from i in properties
                where ((PropertyInfo)i).GetIndexParameters().Length == this.parameters.Length
                select i;

            var e = result.GetEnumerator();
            if (e.MoveNext() && !e.MoveNext())
            {
                // Return the only member that matched the parameter count.
                return e.Current;
            }

            this.ValidateSignature();
            var property = this.instance.GetType().GetProperty(this.memberName, memberBindingFlags, null, typeof(TValue), this.signature, null);

            if (property == null)
            {
                this.ThrowMemberNotFound();
            }

            return property;
        }

        private MemberInfo ResolveMethod(MemberInfo[] methods)
        {
            var result =
                from i in methods
                where ((MethodInfo)i).GetParameters().Length == this.parameters.Length
                select i;

            var e = result.GetEnumerator();
            if (e.MoveNext() && !e.MoveNext())
            {
                // Return the only member that matched the parameter count.
                return e.Current;
            }

            this.ValidateSignature();

            var method = this.instance.GetType().GetMethod(this.memberName, memberBindingFlags, null, this.signature, null);

            if (method == null)
            {
                this.ThrowMemberNotFound();
            }

            return method;
        }

        private void ValidateSignature()
        {
            foreach (var t in this.signature)
            {
                if (t == null)
                {
                    throw new NotSupportedException("The signature of the member must be specified.");
                }
            }
        }

        /// <summary>
        /// Compiles a function that can be used to set the
        /// value of the specified field or property to instances
        /// of the type TInstance.
        /// </summary>
        /// <returns>The compiled function.</returns>
        public Func<TInstance, TValue> CompileGetter()
        {
            MemberInfo member = this.GetMember();

            if (member.MemberType == MemberTypes.Field)
            {
                return this.CompileFieldGetter((FieldInfo)member);
            }

            if (member.MemberType == MemberTypes.Property)
            {
                return this.CompilePropertyGetter((PropertyInfo)member);
            }

            throw new InvalidOperationException("A getter can only be compiled for fields and non indexed properties.");
        }

        private Func<TInstance, TValue> CompilePropertyGetter(PropertyInfo property)
        {
            Type[] argumentTypes = new Type[] { typeof(TInstance) };
            DynamicMethod method = new DynamicMethod(string.Concat("GetProperty_", property.Name), typeof(TValue), argumentTypes, true);
            var getMethod = property.GetGetMethod(true);
            var gen = method.GetILGenerator(256);

            gen.Emit(OpCodes.Ldarg_0);
            gen.EmitCall(OpCodes.Callvirt, getMethod, null);

            if (!getMethod.ReturnType.Equals(typeof(TValue)) && !getMethod.ReturnType.IsClass)
            {
                gen.Emit(OpCodes.Box, getMethod.ReturnType);
            }

            gen.Emit(OpCodes.Ret);

            return method.CreateDelegate<Func<TInstance, TValue>>();
        }

        private Func<TInstance, TValue> CompileFieldGetter(FieldInfo field)
        {
            Type[] argumentTypes = new Type[] { typeof(TInstance) };
            DynamicMethod method = new DynamicMethod(string.Concat("GetField_", field.Name), typeof(TValue), argumentTypes, true);
            var gen = method.GetILGenerator(256);

            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Ldfld, field);

            if (!field.FieldType.Equals(typeof(TValue)) && !field.FieldType.IsClass)
            {
                gen.Emit(OpCodes.Box, field.FieldType);
            }

            gen.Emit(OpCodes.Ret);

            return method.CreateDelegate<Func<TInstance, TValue>>();
        }

        /// <summary>
        /// Compiles a method that can be called throught the 
        /// returned delegate to set the value of the member on
        /// the object specified in method.
        /// </summary>
        /// <returns>A delegate to the compiled method.</returns>
        public Action<TInstance, TValue> CompileSetter()
        {
            MemberInfo member = this.GetMember();

            if (member.MemberType == MemberTypes.Field)
            {
                return this.CompileFieldSetter((FieldInfo)member);
            }

            if (member.MemberType == MemberTypes.Property)
            {
                return this.CompilePropertySetter((PropertyInfo)member);
            }

            throw new InvalidOperationException("A setter can only be compiled for fields and non indexed properties.");
        }

        private Action<TInstance, TValue> CompilePropertySetter(PropertyInfo propertyInfo)
        {
            Type[] argumentTypes = new Type[] { typeof(TInstance), typeof(TValue) };
            DynamicMethod method = new DynamicMethod(string.Concat("SetProperty_", this.GetMember().Name), null, argumentTypes, true);
            MethodInfo setMethod = propertyInfo.GetSetMethod(true);

            var gen = method.GetILGenerator();
            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Ldarg_1);
            gen.EmitCall(OpCodes.Callvirt, setMethod, null);
            gen.Emit(OpCodes.Ret);

            return method.CreateDelegate<Action<TInstance, TValue>>();
        }

        private Action<TInstance, TValue> CompileFieldSetter(FieldInfo field)
        {
            Type[] argumentTypes = new Type[] { typeof(TInstance), typeof(TValue) };
            DynamicMethod method = new DynamicMethod(string.Concat("SetField_", this.GetMember().Name), null, argumentTypes, true);

            var gen = method.GetILGenerator();
            gen.Emit(OpCodes.Ldarg_0);

            if (!typeof(TInstance).Equals(this.instance.GetType()))
            {
                if (typeof(TInstance).IsClass && !this.instance.GetType().IsClass)
                {
                    gen.Emit(OpCodes.Box, this.instance.GetType());
                }
                gen.Emit(OpCodes.Castclass, this.instance.GetType());
            }

            gen.Emit(OpCodes.Ldarg_1);

            if (!typeof(TValue).Equals(field.FieldType))
            {
                if (typeof(TValue).IsClass && !field.FieldType.IsClass)
                {
                    gen.Emit(OpCodes.Unbox_Any, field.FieldType);
                }
                else
                {
                    gen.Emit(OpCodes.Castclass, field.FieldType);
                }
            }

            gen.Emit(OpCodes.Stfld, field);
            gen.Emit(OpCodes.Ret);

            return method.CreateDelegate<Action<TInstance, TValue>>();
        }

        /// <summary>
        /// Compiles a static method that takes the instance on wich the
        /// method will be invoked as the first parameter and then the
        /// parameters of the instance method as the following parameters.
        /// </summary>
        /// <typeparam name="TDelegate">The type of delegate to create.</typeparam>
        /// <returns>The compiled method as a delegate.</returns>
        public TDelegate CompileMethod<TDelegate>() where TDelegate : class
        {
            MethodInfo info = (MethodInfo)this.GetMember();

            List<Type> argumentTypes = new List<Type>();
            argumentTypes.Add(typeof(TInstance));

            foreach (var p in info.GetParameters())
            {
                argumentTypes.Add(p.ParameterType);
            }

            DynamicMethod method = new DynamicMethod(string.Concat("Call_", info.Name), info.ReturnType, argumentTypes.ToArray());
            var gen = method.GetILGenerator();

            for (int i = 0; i < argumentTypes.Count; i++)
            {
                gen.Emit(OpCodes.Ldarg, i); // parameters.
            }

            gen.EmitCall(OpCodes.Callvirt, info, null);

            gen.Emit(OpCodes.Ret);

            return method.CreateDelegate<TDelegate>();
        }

        private TValue InvokeField(FieldInfo field)
        {
            if (setValueToMember)
            {
                field.SetValue(instance, setValue);
                field.IsOfType(typeof(string));
                return setValue;
            }
            else
            {
                return (TValue)field.GetValue(instance);
            }
        }

        private TValue InvokeProperty(PropertyInfo property)
        {
            if (setValueToMember)
            {
                property.SetValue(instance, setValue, parameters);
                return setValue;
            }
            else
            {
                return (TValue)property.GetValue(instance, parameters);
            }
        }

        private TValue InvokeMethod(MethodInfo method)
        {
            return (TValue)method.Invoke(instance, parameters);
        }
        #endregion
    }

    public static class ReflectionExtensions
    {
        /// <summary>
        /// Calls the member with the specified name on the object.
        /// </summary>
        /// <typeparam name="TValue">The return type of the call.</typeparam>
        /// <typeparam name="TInstance">The type of the instance the member is called on.</typeparam>
        /// <param name="instance">The instance to perform the call on.</param>
        /// <param name="name">The name of the instance member to call.</param>
        /// <returns>The return value of the call - or - null (Nothing in VB) if
        /// the call is to a void (Sub in VB) method.</returns>
        public static MemberCall<TInstance, TValue> Member<TInstance, TValue>(this TInstance instance, string name)
        {
            return new MemberCall<TInstance, TValue>(instance, name);
        }

        /// <summary>
        /// Calls the member with the specified name on the object.
        /// </summary>
        /// <typeparam name="TValue">The type of the field or property or the return
        /// value of the method specified by the member name.</typeparam>
        /// <typeparam name="TInstance">The type the member will be called on.</typeparam>
        /// <param name="instance">The instance to perform the call on.</param>
        /// <param name="name">The name of the instance member to call.</param>
        /// <param name="ignored">A value of the type of the members return value, used only
        /// to get the type for the generic TValue type parameter.</param>
        /// <returns>The return value of the call - or - null (Nothing in VB) if
        /// the call is to a void (Sub in VB) method.</returns>
        public static MemberCall<TInstance, TValue> Member<TInstance, TValue>(this TInstance instance, string name, TValue ignored)
        {
            return new MemberCall<TInstance, TValue>(instance, name);
        }

        /// <summary>
        /// Calls the member with the specified name on the object.
        /// </summary>
        /// <typeparam name="TInstance">The type the member will be called on.</typeparam>
        /// <param name="instance">The instance to perform the call on.</param>
        /// <param name="name">The name of the instance member to call.</param>
        /// <returns>The return value of the call - or - null (Nothing in VB) if
        /// the call is to a void (Sub in VB) method.</returns>
        public static MemberCall<TInstance, object> Member<TInstance>(this TInstance instance, string name)
        {
            return new MemberCall<TInstance, object>(instance, name);
        }

        /// <summary>
        /// Completes the dynamic method and creates a delegate that can be
        /// used to call it.
        /// </summary>
        /// <typeparam name="T">The type of delegate to create.</typeparam>
        /// <param name="method">The method that the delegate is created for.</param>
        /// <returns>The created delegate.</returns>
        public static T CreateDelegate<T>(this DynamicMethod method) where T : class
        {
            return (T)(object)method.CreateDelegate(typeof(T));
        }

        /// <summary>
        /// Gets whether the object is of the specified type. An object is
        /// of the specified type if it is an instance of that direct type or
        /// if it is an instance of a class that is in the inheritance hierarchy
        /// of the specified type or if it implements an interface type
        /// that the type represents.
        /// </summary>
        /// <param name="instance">The instance to thest.</param>
        /// <param name="type">The type to check if this object is an instance of.</param>
        /// <returns>True or false.</returns>
        public static bool IsOfType(this object instance, Type type)
        {
            if (instance == null)
                throw new ArgumentNullException("instance");
            if (type == null)
                throw new ArgumentNullException("type");

            return type.IsAssignableFrom(instance.GetType());
        }

        /// <summary>
        /// Gets whether the object is of the specified type. An object is
        /// of the specified type if it is an instance of that direct type or
        /// if it is an instance of a class that is in the inheritance hierarchy
        /// of the specified type or if it implements an interface type
        /// that the type represents.
        /// </summary>
        /// <param name="instance">The instance to thest.</param>
        /// <typeparam name="T">The type to check if this object is an instance of.</typeparam>
        /// <returns>True or false.</returns>
        public static bool IsOfType<T>(this object instance)
        {
            return instance.IsOfType(typeof(T));
        }
    }
}

Thursday, March 6, 2008

Don't you... forget about me.

How to use RegisterClientScriptResource

I think this is like the third time I've spent more than an hour trying to supply a js-file with the ClientScriptManager.RegisterClientScriptResource method. So here's a little how-to.

  1. Make the js-file an embedded resource by setting the build action in the Properties window.
  2. Add the assembly level WebResourceAttribute for the resource. The name of the resource is a tricky little thing especially since it differs slightly depending between C# and VB, see the section further down about this.
  3. Call the RegisterClientScriptResource-method with a type from the same assembly as the resource is located in as the first argument and the resource name as the second argument anytime before the page is rendered.

Resource name

Resources are named slightly differnetly in C# and VB. In both cases they start with the name of the root namespace of the assembly. Then C# has the folder path (dot-separated). Finally in both cases it ends with the file name of the resource.

For example, let's assume that we have a file named Foo.js located in a folder that's named B, that's in turn located in another folder called A in the assembly Bar, that has the root namespace "Bar". Now the resource will be named in the following in the two languages.

C#
Bar.A.B.Foo.js
VB
Bar.Foo.js
The three times I've spent time on this I've simply forgot about the WebResourceAttribute for the script file, now I've hopefully done that for the last time.

Wednesday, February 27, 2008

Guarding with extension methods

I came up with a little - as far as I'm concerned - cool library consisting of extension methods used to guard input parameters of public methods.

It's always a good idea to validate arguments of public methods and throw exceptions if the validation fails. If you require that a parameter is not null, throw an "ArgumentNullException" if the specified argument is null, this makes debugging so much easier and helps other developers that uses your API. To do this in all public methods is a painstaking and repetitive job but my little library makes it just a bit easier.

For example to validate that the string argument of the following method is not null or empty we'd have to write code something like this:

public static char Foo(string bar)
{
    if (bar == null)
        throw new ArgumentNullException("bar");
    if (bar.Length == 0)
        throw new ArgumentOutOfRangeException("bar");

    return bar[0];
}

Now with my extension methods you'd instead write the following:

public static char Foo(string bar)
{
    bar.ExceptionIfNullOrEmpty("bar");
    return bar[0];
}

We can perform other validations as well, for example, we can validate that a value is within a given range:

public static bool Foo(int i)
{
    // The parameter "i" must be within the range 0-10
    i.ExceptionIfOutOfRange(0, 10, "i"); 
}

By using generics and generic constraints the extension methods only appear on values of types they are applicable to. For example the method that checks if a value is within a specified range is only applicable to values of types that implements the IComparable(T)-interface.

public static void ExceptionIfOutOfRange<T>(this T value,
    T lowerBound, T upperBound, string argumentName) where T : IComparable<T>
{
    if (value.CompareTo(lowerBound) < 0 || value.CompareTo(upperBound) > 0)
    {
        throw new ArgumentOutOfRangeException(argumentName);
    }
}

This means that the method will only be shown in the Intellisense on values that it can be applied to:

image

image

Note that in the first case the variable "o" is of the type "object", and the only applicable method is the one that checks for null. In the second case "o" is of the type "int" and now there are two applicable methods, the one that checks if arguments that implements IComparable(T) are within a specified range and the one that checks if an index (int) is within a specified range. Since int is a value type it can't be null so the ExceptionIfNull(T)-method is not applicable, this is little piece of magic is accomplished by the generic constraint "where T : class" that set on the ExceptionIfNull(T)-method.

And here's the code:

#region Using Directives
using System;
using System.Globalization; 
#endregion

namespace Minimal
{
    /// <summary>
    /// Provides helper extension methods for conditional throwing of
    /// exceptions. Mainly used for guarding input parameters.
    /// </summary>
    public static class ThrowHelper
    {
        /// <summary>
        /// Throws an ArgumentNullException if the value is null.
        /// </summary>
        /// <typeparam name="T">The type of the value.</typeparam>
        /// <param name="value">The value to check for null.</param>
        /// <param name="argumentName">The name of the argument the value represents.</param>
        /// <exception cref="ArgumentNullException">The value is null.</exception>
        public static void ExceptionIfNull<T>(this T value, string argumentName) where T : class
        {
            if (value == null)
            {
                throw new ArgumentNullException(argumentName);
            }
        }

        /// <summary>
        /// Throws an ArgumentNullException if the value is null.
        /// </summary>
        /// <typeparam name="T">The type of the value.</typeparam>
        /// <param name="value">The value to check for null.</param>
        /// <param name="argumentName">The name of the argument the value represents.</param>
        /// <param name="message">A message for the exception.</param>
        /// <exception cref="ArgumentNullException">The value is null.</exception>
        public static void ExceptionIfNull<T>(this T value, string argumentName, string message) where T : class
        {
            if (value == null)
            {
                throw new ArgumentNullException(argumentName, message);
            }
        }

        /// <summary>
        /// Throws an ArgumentNullException if the specified value is null or
        /// throws an ArgumentOutOfRangeException if the specified value is an
        /// empty string.
        /// </summary>
        /// <param name="value">The string to check for null or empty.</param>
        /// <param name="argumentName">The name of the argument the value represents.</param>
        /// <exception cref="ArgumentNullException">The value is null.</exception>
        /// <exception cref="ArgumentOutOfRangeException">The value is an empty string.</exception>
        public static void ExceptionIfNullOrEmpty(this string value,
            string argumentName)
        {
            value.ExceptionIfNull("value");

            if (value.Length == 0)
            {
                throw new ArgumentOutOfRangeException(argumentName,
                    string.Format(CultureInfo.InvariantCulture,
                        "The length of the string '{0}' may not be 0.", argumentName ?? string.Empty));
            }
        }

        /// <summary>
        /// Throws an ArgumentOutOfRangeException if the specified value is not within the range
        /// specified by the lowerBound and upperBound parameters.
        /// </summary>
        /// <typeparam name="T">The type of the value.</typeparam>
        /// <param name="value">The value to check that it's not out of range.</param>
        /// <param name="lowerBound">The lowest value that's considered being within the range.</param>
        /// <param name="upperBound">The highest value that's considered being within the range.</param>
        /// <param name="argumentName">The name of the argument the value represents.</param>
        /// <exception cref="ArgumentOutOfRangeException">The value is not within the given range.</exception>
        public static void ExceptionIfOutOfRange<T>(this T value,
            T lowerBound, T upperBound, string argumentName) where T : IComparable<T>
        {
            if (value.CompareTo(lowerBound) < 0 || value.CompareTo(upperBound) > 0)
            {
                throw new ArgumentOutOfRangeException(argumentName);
            }
        }


        /// <summary>
        /// Throws an ArgumentOutOfRangeException if the specified value is not within the range
        /// specified by the lowerBound and upperBound parameters.
        /// </summary>
        /// <typeparam name="T">The type of the value.</typeparam>
        /// <param name="value">The value to check that it's not out of range.</param>
        /// <param name="lowerBound">The lowest value that's considered being within the range.</param>
        /// <param name="upperBound">The highest value that's considered being within the range.</param>
        /// <param name="argumentName">The name of the argument the value represents.</param>
        /// <param name="message">A message for the exception.</param>
        /// <exception cref="ArgumentOutOfRangeException">The value is not within the given range.</exception>
        public static void ExceptionIfOutOfRange<T>(this T value,
            T lowerBound, T upperBound, string argumentName, string message) where T : IComparable<T>
        {
            if (value.CompareTo(lowerBound) < 0 || value.CompareTo(upperBound) > 0)
            {
                throw new ArgumentOutOfRangeException(argumentName, message);
            }
        }

        /// <summary>
        /// Throws an IndexOutOfRangeException if the specified index is not within the range
        /// specified by the lowerBound and upperBound parameters.
        /// </summary>
        /// <param name="index">The index to check that it's not out of range.</param>
        /// <param name="lowerBound">The lowest value considered being within the range.</param>
        /// <param name="upperBound">The highest value considered being within the range.</param>
        /// <param name="argumentName">The name of the argument the value represents.</param>
        /// <exception cref="IndexOutOfRangeException">The index is not within the given range.</exception>
        public static void ExceptionIfIndexOutOfRange(this int index,
            int lowerBound, int upperBound, string argumentName)
        {
            if (index < lowerBound || index > upperBound)
            {
                throw new IndexOutOfRangeException();
            }
        }

        /// <summary>
        /// Throws an IndexOutOfRangeException if the specified index is not within the range
        /// specified by the lowerBound and upperBound parameters.
        /// </summary>
        /// <param name="index">The index to check that it's not out of range.</param>
        /// <param name="lowerBound">The lowest value considered being within the range.</param>
        /// <param name="upperBound">The highest value considered being within the range.</param>
        /// <param name="argumentName">The name of the argument the value represents.</param>
        /// <exception cref="IndexOutOfRangeException">The index is not within the given range.</exception>
        public static void ExceptionIfIndexOutOfRange(this long index,
            long lowerBound, long upperBound, string argumentName)
        {
            if (index < lowerBound || index > upperBound)
            {
                throw new IndexOutOfRangeException();
            }
        }
    }
}

Tuesday, February 12, 2008

Exposing collections

Keyvan Nayyeri has a blog post about exposing generic collections rather than lists in API's.

The basis of his post is that he says that it's a bad idea to expose List<T> publicly, I couldn't agree more. Actually I think it's such a bad idea that I didn't realize that it was a wide spread habit. If you're going to expose a collection it should be exposed in one of two ways in my opinion.

  1. The best alternative in most cases is a strongly typed collection named after what it contains (for example StudentCollection contains Student-objects), that implements at least the IEnumerable<Student> or more specific interfaces (ICollection<Student> or IList<Student>) if so needed.
  2. Expose the collections interface, not the implementation and don't specialize the interface more than needed. If the api just exposes a collection of students in no particular order and it should be read only expose it as an IEnumerable<Student>, not ICollection<Student> or IList<Student>.

Also when you take collections as parameters in your methods use the strongly typed collection or interfaces.

EDIT: I've found that there is actually a generic counterpart of the System.Collections.CollectionBase-class, which can be found in the namespace System.Collections.ObjectModel and it's simply called Collection<T>. This saves us the labor of having to implement our own such base class but the principles in this article still holds true.

Before generics were introduced in .net the simplest way to implement a strongly typed collection was to inherit from the System.Collections.CollectionBase-class, for some reason there is no generic version of this class so I've created one of my own (that implements bot the ICollection<T> and the ICollection interfaces). The nice thing about this abstract class is that it uses explicit interface implementation so none of the interface-methods are exposed (if the collection is not cast to the interface) this allows the developer to expose only the wanted methods through the API. The benefit of this is a much clearer API that is a lot easier to use with Intellisense since only the defined methods are shown.

For example to implement a FooCollection you'd inherit from the CollectionBase<T> class as follows:

public class Foo
{

}

public class FooCollection
    : CollectionBase<Foo>
{
    public void Add(Foo item)
    {
        this.InnerCollection.Add(item);
    }

    protected override ICollection<Foo> CreateInnerCollection()
    {
        return new List<Foo>();
    }
}

In this way we have created a strongly typed collection that also implements both the ICollection<Foo> and the non generic ICollection interfaces we also only expose the Add-method keeping the intellisense simple and public API simple (of course all interface methods are implemented and accessible through a cast).

My implementation of CollectionBase<T> is shown below.

/// <summary>
/// An abstract base class used to create strongly typed collections.
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
public abstract class CollectionBase<T> :
    ICollection<T>, ICollection
{
    #region Constructor
    /// <summary>
    /// Creates a new instance.
    /// </summary>
    protected CollectionBase()
    {            
        this.InnerCollection = this.CreateInnerCollection();
    }

    /// <summary>
    /// Creates a new instance and sets the inner collection to the supplied
    /// collection.
    /// </summary>
    /// <param name="innerCollection">The collection to use to store
    /// the items internally.</param>
    /// <exception cref="ArgumentNullException">Thrown if the innerCollection parameter
    /// is null (Nothing in VB).</exception>
    protected CollectionBase(ICollection<T> innerCollection)
    {
        if (innerCollection == null)
            throw new ArgumentNullException("innerCollection");

        this.InnerCollection = innerCollection;
    }
    #endregion

    #region Properties
    #region InnerCollection
    [DebuggerBrowsable(DebuggerBrowsableState.Never), EditorBrowsable(EditorBrowsableState.Never)]
    private ICollection<T> _innerCollection;

    /// <summary>
    /// A collection that stores the items internally.
    /// </summary>
    protected ICollection<T> InnerCollection
    {
        [DebuggerStepThrough]
        get { return _innerCollection; }
        [DebuggerStepThrough]
        set { _innerCollection = value; }
    }
    #endregion InnerCollection
    #endregion

    #region Methods
    #region CreateInnerCollection
    /// <summary>
    /// When implemented by a sub class this method creates a collection
    /// that can be used as inner collection.
    /// </summary>
    /// <returns>A new ICollecion instance.</returns>
    protected abstract ICollection<T> CreateInnerCollection(); 
    #endregion CreateInnerCollection
    #endregion Methods

    #region ICollection<T> Members

    void ICollection<T>.Add(T item)
    {
        this.InnerCollection.Add(item);
    }

    void ICollection<T>.Clear()
    {
        this.InnerCollection.Clear();
    }

    bool ICollection<T>.Contains(T item)
    {
        return this.InnerCollection.Contains(item);
    }

    void ICollection<T>.CopyTo(T[] array, int arrayIndex)
    {
        this.InnerCollection.CopyTo(array, arrayIndex);
    }

    /// <summary>
    /// Gets the number of items in the collection.
    /// </summary>
    public int Count
    {
        get { return this.InnerCollection.Count; }
    }

    bool ICollection<T>.IsReadOnly
    {
        get { return this.InnerCollection.IsReadOnly; }
    }

    bool ICollection<T>.Remove(T item)
    {
        return this.InnerCollection.Remove(item);
    }

    #endregion

    #region IEnumerable<T> Members

    public IEnumerator<T> GetEnumerator()
    {
        return this.InnerCollection.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.InnerCollection.GetEnumerator();
    }

    #endregion

    #region ICollection Members

    void ICollection.CopyTo(Array array, int index)
    {
        this.InnerCollection.CopyTo((T[])array, index);
    }

    int ICollection.Count
    {
        get { return this.InnerCollection.Count; }
    }

    bool ICollection.IsSynchronized
    {
        get { return false; }
    }

    object ICollection.SyncRoot
    {
        get { return this.InnerCollection; }
    }

    #endregion
}

 

Technorati-taggar: ,,