Click here to Skip to main content
Email Password   helpLost your password?

Table of contents

Introduction

The CLR and other .NET code contains many recurring patterns. As these patterns appear in code, they may also appear in code generated by CodeDom graphs, yet generating these patterns requires lot of work, which is quite repetitive. This library contains many pattern implementations for use in your own CodeDom generator, which could help you in decreasing the amount of code you write by thousands of lines.
If you believe there is a pattern that would be perfect for the library, leave a comment and chances are good it will be available, come the next release.

As of October 23, 2006, the project is hosted on CodePlex, with this article serving as an introduction to its abilities.

Argument Assertion patterns

The Argument Assertion patterns are recurring patterns from the CLR in which arguments are checked and exceptions such as ArgumentNullException are raised accordingly. The currently supported assertions are: NotNull, InRange, InLowerBound, InUpperBound, IsInstanceOf, EnumIsDefined and StringNotNullOrEmpty.

In order to include this pattern in your code, your code should look like this:

myMethod.Statements.Add(
    new CodePatternArgumentAssertNotNullStatement("myArgument"));
myMethod.Statements.Add(
    new CodePatternArgumentAssertInRangeStatement("myArgument",
        new CodeFieldReferenceExpression(
            new CodeTypeReferenceExpression("MyType"), "MinValue"), 
        new CodeFieldReferenceExpression(
            new CodeTypeReferenceExpression("MyType"), "MaxValue")));
myMethod.Statements.Add(
    new CodePatternArgumentAssertIsInstanceOfStatement(
                                         "myArgument", typeof(int)));

The code generated by above will be:

if ((myArgument == null))
{
    throw new System.ArgumentNullException("myArgument");
}
if (((myArgument > MyType.MaxValue) 
    || (myArgument < MyType.MinValue)))
{
    throw new System.ArgumentOutOfRangeException("myArgument");
}
if ((myArgument.GetType().IsInstanceOfType(typeof(int)) == false))
{
    throw new System.ArgumentException(string.Format(
              "The argument myArgument must be of type {0}.", 
              typeof(int).FullName), "myArgument");
}

The Assembly Information pattern

Added automatically by Visual Studio, an assembly is identifiable by a set of attributes. This pattern simplifies access to these attributes as properties of a class deriving from CodeCompileUnit.

In order to include this pattern in your code, your code should look like this:

CodePatternCompileUnit unit = new CodePatternCompileUnit();
unit.AssemblyVersion = new Version(1, 0);
unit.AssemblyTitle = "My assembly";
unit.CLSCompliant = true;

The code generated by above will be:

[assembly: System.Reflection.AssemblyVersionAttribute("1.0")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0")]
[assembly: System.Reflection.AssemblyTitleAttribute("My assembly")]
[assembly: System.CLSCompliantAttribute(true)]

The Asynchronous Operation pattern

A recurring pattern from the CLR, asynchronous invocation of methods is required by many systems and components. The implementation presented here is the simplest one, which uses delegates. Documentation on the members generated can be controlled using the HasComments property.

In order to include this pattern in your code, your code should look like this:

type.Members.AddRange(new CodePatternAsyncOperation(myMethod));

The code generated by above will be:

/// <summary>

/// Represents the delegate instance

/// for asynchronous calls to MyMethod.

/// </summary>

private MyMethodAsyncCallback m_MyMethodCallback;

/// <summary>

/// Executes the MyMethod method asynchronously with a callback.

/// </summary>

/// <param name="foo">See original method, MyMethod,

/// for more information about this parameter.</param>

/// <param name="callback">A method to be called when

/// the asynchronous action completes.</param>

/// <returns>An <see cref="System.IAsyncResult" />

/// object detailing the asynchronous action.</returns>

public System.IAsyncResult BeginMyMethod(int foo, 
                           System.AsyncCallback callback)
{
    if ((this.m_MyMethodCallback == null))
    {
        this.m_MyMethodCallback = 
                new MyMethodAsyncCallback(this.MyMethod);
    }
    return this.m_MyMethodCallback.BeginInvoke(foo, callback, null);
}

/// <summary>

/// Executes the MyMethod method asynchronously.

/// </summary>

/// <param name="foo">See original method, MyMethod,

/// for more information about this parameter.</param>

/// <returns>An <see cref="System.IAsyncResult" />

/// object detailing the asynchronous action.</returns>

public System.IAsyncResult BeginMyMethod(int foo)
{
    return this.BeginMyMethod(foo, null);
}

/// <summary>

/// Synchronously completes an asynchronous call to MyMethod.

/// </summary>

/// <param name="asyncResult">The <see cref="System.IAsyncResult" />

/// retrieved from the call to <see cref="BeginMyMethod" />.</param>

/// <exception cref="System.InvalidOperationException">Thrown

/// when the method is called before the

/// <see cref="BeginMyMethod" /> method.</exception>

public void EndMyMethod(System.IAsyncResult asyncResult)
{
    if ((this.m_MyMethodCallback == null))
    {
        throw new System.InvalidOperationException("End of asynchronous" + 
                  " operation attempted when one has not yet begun.");
    }
    this.m_MyMethodCallback.EndInvoke(asyncResult);
}

/// <summary>

/// Represents the delegate for asynchronous calls to MyMethod.

/// </summary>

public delegate void MyMethodAsyncCallback(int foo);

The BeginProcess/EndProcess pattern

A recurring pattern from System.Data and System.Windows.Forms is the BeginProcess/EndProcess pattern, such as BeginLoad/EndLoad and BeginInit/EndInit. This pattern enables silencing of events with an intuitive interface. Documentation on the members generated can be controlled using the HasComments property.

In order to include this pattern in your code, your code should look like this:

type.Members.AddRange(new CodePatternBeginEndProcess("Init"));

The code generated by above will be:

/// <summary>

/// See <see cref="IsInInit" />

/// for information about this field.

/// </summary>

private int m_IsInInit;

/// <summary>

/// Begins the Init process.

/// </summary>

public virtual void BeginInit()
{
    this.m_IsInInit = (this.m_IsInInit + 1);
}

/// <summary>

/// Ends the Init process.

/// </summary>

public virtual void EndInit()
{
    if ((this.m_IsInInit != 0))
    {
        this.m_IsInInit = (this.m_IsInInit - 1);
    }
}

/// <summary>

/// Gets whether the Init process has begun.

/// </summary>

/// <value>Whether the init process has begun.</value>

protected bool IsInInit()
{
    return (this.m_IsInInit != 0);
}

Binary Operator patterns

Most binary operators are built into CodeDom, but some aren't. This pattern extends the normal CodeBinaryOperatorExpression to add more operators. Currently supported operator/s: BooleanExclusiveOr.

In order to include this pattern in your code, your code should look like this:

method.Statements.Add(
    new CodeConditionStatement(
        new CodePatternBinaryOperatorExpression(
           new CodeVariableReferenceExpression("bool1"), 
           CodePatternBinaryOperatorType.BooleanExclusiveOr,
           new CodeVariableReferenceExpression("bool2"))
        /* , Contained statements */));

The code generated by above will be:

if (((bool1 == true) && (bool2 == false)) || 
                ((bool1 == false) && (bool2 == true)))
{
    // Contained statements...

}

Code Access Security Decorator patterns

The model of declarative Code Access Security is widespread in the CLR and also very important in many differing situations.

In order to include this pattern in your code, your code should look like this:

UI ui = new DotNetZen.CodeDom.Patterns.Permissions.UI();
ui.Clipboard = 
  System.Security.Permissions.UIPermissionClipboard.AllClipboard;
myMethod.CustomAttributes.Add(new CodePatternCasAttribute(ui));

The code generated by above will be:

[System.Security.Permissions.UIPermissionAttribute(
   System.Security.Permissions.SecurityAction.Demand, 
   Clipboard=System.Security.Permissions.
             UIPermissionClipboard.AllClipboard)]
private void MyMethod()
{
}
Currently all of the Framework's declarative CAS attributes are supported and custom attribute abstractions can be created simply by inheriting from DotNetZen.CodeDom.Patterns.Permissions.Permission.

Compound Assignment patterns

No compound assignment operators are built into CodeDom. This pattern extends the normal CodeAssignStatement to add more operators. Currently supported operator/s: Add, Subtract, Multiply, Divide, Modulus, BitwiseAnd, BitwiseOr.

In order to include this pattern in your code, your code should look like this:

method.Statements.Add(
    new CodePatternCompoundAssignStatement(
        new CodeVariableReferenceExpression("foo"),
        CodePatternCompoundAssignmentOperatorType.Add,
        new CodeVariableReferenceExpression("bar")));

The code generated by above will be:

foo = (foo + bar);

The Cursor Lock pattern

A recurring pattern from System.Windows.Forms is the locking of a Form's Cursor property. This pattern is useful when the process contained within it is quite long.

In order to include this pattern in your code, your code should look like this:

method.Statements.AddRange(
    new CodePatternCursorLock(/* Contained statements */));

The code generated by above will be:

System.Windows.Forms.Cursor cursor0 = this.Cursor;

try
{
    this.Cursor = System.Windows.Forms.Cursors.WaitCursor;
    
    // More code here...

}
finally
{
    this.Cursor = cursor0;
}

The Custom Attribute pattern

Most custom attributes derive from the same template. As a result, creating custom attributes can be a menial task. Documentation on the members generated can be controlled using the HasComments property and the SetComment method.

In order to include this pattern in your code, your code should look like this:

CodePatternCustomAttributeDeclaration attrib = 
      new CodePatternCustomAttributeDeclaration(
          "CoolMetaData",
          AttributeTargets.Struct | 
             AttributeTargets.Class | AttributeTargets.Enum,
          false, true,
          new CodeParameterDeclarationExpression(typeof(int), 
                                               "MetaData"));

attrib.SetComment("MetaData", "The metadata for the attribute");

The code generated by above will be:

[System.AttributeUsageAttribute(((System.AttributeTargets.Enum | 
                                  System.AttributeTargets.Struct) 
        | System.AttributeTargets.Class), 
        AllowMultiple=false, Inherited=true)]
public sealed class CoolMetaDataAttribute : System.Attribute
{
    /// <summary>

    /// Value for the property <see cref="MetaData" />.

    /// </summary>

    private int m_MetaData;

    /// <summary>

    /// Initializes a new instance of the

    /// <see cref="CoolMetaDataAttribute" /> class.

    /// </summary>

    public CoolMetaDataAttribute()
    {
    }

    /// <summary>

    /// Initializes a new instance of the

    /// <see cref="CoolMetaDataAttribute" /> class.

    /// </summary>

    /// <param name="MetaData">The metadata

    /// for the attribute.</param>

    public CoolMetaDataAttribute(int MetaData)
    {
        this.m_MetaData = MetaData;
    }

    /// <summary>

    /// Gets the metadata for the attribute.

    /// </summary>

    /// <value>The metadata for the attribute.</value>

    public int MetaData
    {
        get
        {
            return this.m_MetaData;
        }
    }
}

The Custom Exception pattern

Most custom exceptions derive from the same template. As a result, creating custom exceptions can be a menial task. Documentation on the members generated can be controlled using the HasComments property and the SetComment method.

In order to include this pattern in your code, your code should look like this:

CodePatternCustomExceptionDeclaration exception = 
    new CodePatternCustomExceptionDeclaration("Foo",
        new CodeParameterDeclarationExpression(
                               typeof(int), "Bar"));

exception.SetComment("Bar", "A healthy snack-bar");

The code generated by above will be:

[System.SerializableAttribute()]
public class FooException : System.Exception
{
    /// <summary>

    /// Value for the property <see cref="Bar" />.

    /// </summary>

    private int m_Bar;

    /// <summary>

    /// Initializes a new instance of the <see cref="FooException" /> class.

    /// </summary>

    /// <param name="Bar">A healthy snack-bar.</param>

    public FooException(int Bar)
    {
        this.m_Bar = Bar;
    }

    /// <summary>

    /// Initializes a new instance of the <see cref="FooException" /> class.

    /// </summary>

    /// <param name="Bar">A healthy snack-bar.</param>

    /// <param name="message">The message in the exception.</param>

    public FooException(int Bar, string message) : 
        base(message)
    {
        this.m_Bar = Bar;
    }

    /// <summary>

    /// Initializes a new instance of the <see cref="FooException" /> class.

    /// </summary>

    /// <param name="info">The data needed to serialize

    /// or deserialize an object.</param>

    /// <param name="context">The source and destination

    /// of a given serialized stream.</param>

    /// <remarks>This member supports the .NET Framework infrastructure

    /// and is not intended to be used directly from your code.</remarks>

    protected FooException(System.Runtime.Serialization.SerializationInfo info, 
              System.Runtime.Serialization.StreamingContext context) : 
              base(info, context)
    {
        this.m_Bar = ((int)(info.GetValue("m_Bar", typeof(int))));
    }

    /// <summary>

    /// Initializes a new instance of the <see cref="FooException" /> class.

    /// </summary>

    /// <param name="Bar">A healthy snack-bar.</param>

    /// <param name="message">The message in the exception.</param>

    /// <param name="innerException">An exception

    /// encapsulated in the new exception.</param>

    public FooException(int Bar, string message, 
           System.Exception innerException) : 
           base(message, innerException)
    {
        this.m_Bar = Bar;
    }

    /// <summary>

    /// Gets a healthy snack-bar.

    /// </summary>

    /// <value>A healthy snack-bar.</value>

    public int Bar
    {
        get
        {
            return this.m_Bar;
        }
    }

    /// <summary>

    /// Populates a <see
    /// cref="System.Runtime.Serialization.SerializationInfo" />

    /// with the data needed to serialize the target object.

    /// </summary>

    /// <param name="info">The <see 
    ///      cref="System.Runtime.Serialization.SerializationInfo" />

    /// to populate with data.</param>

    /// <param name="context">The destination

    /// (see <see cref="System.Runtime.Serialization.StreamingContext" />)

    /// for this serialization.</param>

    /// <exception cref="System.ArgumentNullException">Thrown when

    /// the <paramref name="info" /> parameter is a null reference

    /// (Nothing in Visual Basic).</exception>

    [System.Security.Permissions.SecurityPermissionAttribute(
        System.Security.Permissions.SecurityAction.LinkDemand, 
        Flags=System.Security.Permissions.
              SecurityPermissionFlag.SerializationFormatter)]
    public override void GetObjectData(
                    System.Runtime.Serialization.SerializationInfo 
                    info, 
                    System.Runtime.Serialization.StreamingContext context)
    {
        base.GetObjectData(info, context);
        info.AddValue("m_Bar", this.m_Bar, typeof(int));
    }
}

The Delegate pattern

The Delegate pattern, also known as the EventHandler pattern, is a recurring pattern from the CLR, in which a delegate is created with an object and EventArgs, with a specialized EventArgs class. This pattern is useful for the quick creation of any delegate. Documentation on the members generated can be controlled using the HasComments property and the SetComment method.

In order to include this pattern in your code, your code should look like this:

CodePatternDelegate delegateType = new CodePatternDelegate(
    "ItemChanged",
    new CodeParameterDeclarationExpression(typeof(int), "OldValue"),
    new CodeParameterDeclarationExpression(typeof(int), "NewValue"));

delegateType.SetComment("OldValue", "The value before the change");
delegateType.SetComment("NewValue", "The value after the change");

nameSpace.Types.AddRange(delegateType);

The code generated by above will be:

/// <summary>

/// Represents a method that takes a <see cref="System.Object" />

/// and <see cref="ItemChangedEventArgs" />.

/// </summary>

/// <param name="sender">The event's originating object.</param>

/// <param name="e">The event's arguments.</param>

public delegate void ItemChangedEventHandler(object sender, 
                                    ItemChangedEventArgs e);

/// <summary>

/// Contains the arguments for events based

/// on the <see cref="ItemChangedEventHandler" /> delegate.

/// </summary>

public class ItemChangedEventArgs : System.EventArgs
{
    
    /// <summary>

    /// Value for the property <see cref="OldValue" />.

    /// </summary>

    private int m_OldValue;
    
    /// <summary>

    /// Value for the property <see cref="NewValue" />.

    /// </summary>

    private int m_NewValue;
    
    /// <summary>

    /// Initializes a new instance of the

    /// <see cref="ItemChangedEventArgs" /> class.

    /// </summary>

    /// <param name="OldValue">The value before the change.</param>

    /// <param name="NewValue">The value after the change.</param>

    public ItemChangedEventArgs(int OldValue, int NewValue)
    {
        this.m_OldValue = OldValue;
        this.m_NewValue = NewValue;
    }
    
    /// <summary>

    /// Gets the value before the change.

    /// </summary>

    /// <value>The value before the change.</value>

    public virtual int OldValue
    {
        get
        {
            return this.m_OldValue;
        }
    }
    
    /// <summary>

    /// Gets the value after the change.

    /// </summary>

    /// <value>The value after the change.</value>

    public virtual int NewValue
    {
        get
        {
            return this.m_NewValue;
        }
    }
}

The Disposable Type pattern

A recurring pattern from the CLR, this recommended pattern for use of the IDisposable interface is used to keep finalizers from running when the object has already been disposed. Documentation on the members generated can be controlled using the automaticComments parameter.
In order to implement the pattern in types that derive from types already implementing this pattern, use the DisposeImplementationType.Inherited value and only an override for void Dispose(bool) will be created.

In order to include this pattern in your code, your code should look like this:

CodePatternTypeDeclaration declaration = 
            new CodePatternTypeDeclaration("MyType");
// ...

declaration.ApplyDisposablePattern(
     new CodeInstanceReferenceExpression(new 
     CodeFieldReferenceExpression(new CodeThisReferenceExpression(), 
     "myReferenceTypeField"), typeof(object)), 
     new CodeInstanceReferenceExpression(new 
     CodeFieldReferenceExpression(new CodeThisReferenceExpression(), 
     "myValueTypeField"), typeof(int)));

The code generated by above will be:

public class MyType : System.IDisposable
{
    /// <summary>

    /// Releases all resources used by the object.

    /// </summary>

    public void Dispose()
    {
        this.Dispose(true);
        System.GC.SuppressFinalize(this);
    }

    /// <summary>

    /// Releases the unmanaged resources used by the object

    /// and optionally releases the managed resources.

    /// </summary>

    /// <param name="disposing">true to release both managed

    /// and unmanaged resources; false

    /// to release only unmanaged resources.</param>

    /// <remarks>This method is called by the public

    /// <see cref="Dispose()" /> method and the Finalize method.

    /// <see cref="Dispose" /> invokes the protected

    /// <see cref="Dispose(System.Boolean)" /> method with

    /// the <paramref name="disposing" /> parameter set to true.

    /// Finalize invokes Dispose with

    /// <paramref name="disposing" /> set to false.

    /// When the <paramref name="disposing" /> parameter is true,

    /// this method releases all resources held

    /// by any managed objects that this object references.

    /// This method invokes the <see cref="Dispose()" />

    /// method of each referenced object.

    /// Notes to Inheritors: This method can be called multiple times

    /// by other objects. When overriding it, be careful not to reference

    /// objects that have been previously

    /// disposed of in an earlier call.</remarks>

    protected virtual void Dispose(bool disposing)
    {
        if ((disposing == true))
        {
            if ((this.myReferenceTypeField != null))
            {
                ((System.IDisposable)(this.myReferenceTypeField)).Dispose();
            }
            ((System.IDisposable)(this.myValueTypeField)).Dispose();
        }
    }
}

Please note that due to a bug in the .NET Framework, Creation of finalizers is impossible! Please vote on this issue on LadyBug.

The Event pattern

The Event pattern is a recurring pattern from System.Windows.Forms, in which an event has a special invoking method. This pattern is useful for the quick creation of any event. Documentation on the members generated can be controlled using the HasComments property.

In order to include this pattern in your code, your code should look like this:

type.Members.AddRange(new CodePatternEvent(
    "EventHappened", Scope.Instance, typeof(EventHandler)));

The code generated by above will be:

public event System.EventHandler EventHappened;

/// <summary>

/// Raises the <see cref="EventHappened" /> event.

/// </summary>

/// <param name="e">The value passed

/// for the event's e parameter.</param>

protected virtual int OnEventHappened(System.EventArgs e)
{
    if ((this.EventHappened != null))
    {
        this.EventHappened(this, e);
    }
}

Please note that due to a bug in the .NET Framework, static events cannot be generated! Please vote on this issue on LadyBug.

Language restrictions: Visual Basic does not allow return values from events.

The Flags pattern

The Flags pattern is a recurring pattern from the entire CLR, in which an enum is flagged with the FlagsAttribute attribute. This pattern allocates values automatically and supports up to 63 values.
Each member's CodeMemberField object can be accessed using the Flags indexer.

In order to include this pattern in your code, your code should look like this:

nameSpace.Types.Add(new CodePatternFlags("MyFlags", 
                                      "A", "B", "C"));

The code generated by above will be:

[System.FlagsAttribute()]
public enum MyFlags : int
{
    A = 1,
    B = 2,
    C = 4,
}

The For Each pattern

The For Each pattern is built into C#, but is not native to IL. The pattern iterates over a collection that implements the System.IEnumerable interface. As the C# specification states, the implementation of the said interface is not required, but the implementation of the methods such as MoveNext and GetEnumerator are.

In order to include this pattern in your code, your code should look like this:

method.Statements.AddRange(new CodePatternForEach(
    new CodeTypeReference(typeof(int)), 
    new CodeVariableReferenceExpression("myCollection"),
    new CodeTypeReference("EnumeratorType")
    /* , Contained statements */));

The code generated by above will be:

System.Collections.IEnumerator enumerator0 = 
  ((System.Collections.IEnumerator)(myCollection)).GetEnumerator();

try
{
    for (; enumerator0.MoveNext();)
    {
        int element0 = ((int)(enumerator0.Current));
        // Contained statements ...

    }
}
finally
{
    if (((enumerator0 != null) && 
          enumerator0.GetType().IsInstanceOfType(
                      typeof(System.IDisposable))))
    {
        ((System.IDisposable)(enumerator0)).Dispose();
    }
}

The Get Property/Field pattern

The Get Property/Field pattern is a recurring pattern from the entire CLR, in which a private field is exposed using a property with a get accessor.

In order to include this pattern in your code, your code should look like this:

type.Members.AddRange(new CodePatternGetField("Value", 
    new CodeTypeReference(typeof(int)), Scope.Instance));

The code generated by above will be:

private int m_Value;

public int Value
{
    get
    {
        return this.m_Value;
    }
}

The Is Instance Of pattern

The Is Instance Of pattern is built into C# as the is keyword, and is also native to IL, yet it is not implemented in CodeDom. The pattern checks whether an object's type implements, inherits or is the queried type.

In order to include this pattern in your code, your code should look like this:

method.Statements.Add(new CodePatternIsInstExpression(
          new CodeVariableReferenceExpression("myVariable"),
          new CodeTypeReference(typeof(IMyInterface))));

The code generated by above will be:

myVariable.GetType().IsInstanceOfType(typeof(IMyInterface))

The Lock pattern

The Lock pattern is built into C#, but is not native to IL. The pattern locks a resource using the System.Threading.Monitor class.

In order to include this pattern in your code, your code should look like this:

method.Statements.AddRange(new CodePatternLock(
          new CodeFieldReferenceExpression(
               new CodeThisReferenceExpression(), "SyncRoot")
          /* , Contained statements... */));

The code generated by above will be:

object lockCachedExpr0 = this.SyncRoot;
System.Threading.Monitor.Enter(lockCachedExpr0);

try
{
    // Contained statements...

}
finally
{
    System.Threading.Monitor.Exit(lockCachedExpr0);
}

The Nullable Value Type Property pattern

The Nullable Value Type Property pattern is used in CLR 1.x (pre-generics and Nullable<T>) to denote a value type property with a null value. This pattern is used predominately in Typed DataSets.

In order to include this pattern in your code, your code should look like this:

type.Members.AddRange(new CodePatternNullableProperty("Value", 
         new CodeTypeReference(typeof(int)), Scope.Instance));

The code generated by above will be:

private int m_Value;

/// <summary>

/// See <see cref="IsValueNull" /> for information about this field.

/// </summary>

private bool m_IsValueNull = true;

public int Value
{
    get
    {
        if ((this.m_IsValueNull == true))
        {
            throw new System.InvalidOperationException("Can not" + 
                  " get value when it is null. Check for " + 
                  "nullability by calling IsValueNull.");
        }
        return this.m_Value;
    }
    set
    {
        this.m_Value = value;
        this.m_IsValueNull = false;
    }
}

/// <summary>

/// Gets whether the value of <see cref="Value" /> is null.

/// </summary>

/// <value>Whether the value of <see cref="Value" /> is null.</value>

public bool IsValueNull
{
    get
    {
        return this.m_IsValueNull;
    }
}

/// <summary>

/// Sets the value of <see cref="Value" /> to null.

/// </summary>

public void SetValueNull()
{
    this.m_IsValueNull = true;
}

The Observer pattern

The Observer pattern is a classic pattern which allows subscribers to be notified of the changes to a value. This implementation allows changes to the value of a property to be announced using an event. Documentation on the members generated can be controlled using the HasComments property.

In order to include this pattern in your code, your code should look like this:

type.Members.AddRange(new CodePatternObserver("MyValue", 
    new CodeTypeReference(typeof(int)), Scope.Instance));

The code generated by above will be:

/// <summary>

/// Value for the property <see cref="MyValue" />.

/// </summary>

private int m_MyValue;

public int MyValue
{
    get
    {
        return this.m_MyValue;
    }
    set
    {
        if ((this.m_MyValue != value))
        {
            int oldValue = this.m_MyValue;
            this.m_MyValue = value;
            this.OnMyValueChanged(new MyValueChangedEventArgs(oldValue, 
                                                        this.m_MyValue));
        }
    }
}

/// <summary>

/// Occurs when the <see cref="MyValue" /> property is changed.

/// </summary>

public event MyValueChangedEventHandler MyValueChanged;

/// <summary>

/// Raises the <see cref="MyValueChanged" /> event.

/// </summary>

/// <param name="e">The value passed

/// for the event's e parameter.</param>

protected virtual void OnMyValueChanged(MyValueChangedEventArgs e)
{
    if ((this.MyValueChanged != null))
    {
        this.MyValueChanged(this, e);
    }
}

/// <summary>

/// Represents a method that takes a <see cref="System.Object" />

/// and <see cref="MyValueChangedEventArgs" />.

/// </summary>

/// <param name="sender">The event's originating object.</param>

/// <param name="e">The event's arguments.</param>

public delegate void MyValueChangedEventHandler(object sender, 
                                   MyValueChangedEventArgs e);

/// <summary>

/// Contains the arguments for events based

/// on the <see cref="MyValueChangedEventHandler" /> delegate.

/// </summary>

public class MyValueChangedEventArgs : System.EventArgs
{
    /// <summary>

    /// Value for the property <see cref="OldValue" />.

    /// </summary>

    private int m_OldValue;

    /// <summary>

    /// Value for the property <see cref="NewValue" />.

    /// </summary>

    private int m_NewValue;

    /// <summary>

    /// Initializes a new instance

    /// of the <see cref="MyValueChangedEventArgs" /> class.

    /// </summary>

    /// <param name="OldValue">The value before the change.</param>

    /// <param name="NewValue">The current value.</param>

    public MyValueChangedEventArgs(int OldValue, int NewValue)
    {
        this.m_OldValue = OldValue;
        this.m_NewValue = NewValue;
    }

    /// <summary>

    /// Gets the value before the change.

    /// </summary>

    /// <value>The value before the change.</value>

    public virtual int OldValue
    {
        get
        {
            return this.m_OldValue;
        }
    }

    /// <summary>

    /// Gets the current value.

    /// </summary>

    /// <value>The current value.</value>

    public virtual int NewValue
    {
        get
        {
            return this.m_NewValue;
        }
    }
}

The Serializable Type pattern

A pattern from the CLR, this pattern applies one of the four different types of serialization in the framework: Basic, Selective and Custom for types new to serialization and ones inheriting it. Documentation on the members generated can be controlled using the automaticComments parameter.

In order to include this pattern in your code, your code should look like this:

CodePatternTypeDeclaration declaration = 
                     new CodePatternTypeDeclaration("MyType");
decl.Members.Add(new CodeMemberField(typeof(int), "myField"));
decl.ApplySerializablePattern(SerializationType.NewCustom, "myField");

The code generated by above will be:

[System.SerializableAttribute()]
public class MyType : System.Runtime.Serialization.ISerializable
{
    private int myField;

    /// <summary>

    /// Initializes a new instance of the <see cref="MyType" /> class.

    /// </summary>

    /// <param name="info">The data needed

    /// to serialize or deserialize an object.</param>

    /// <param name="context">The source

    /// and destination of a given serialized stream.</param>

    /// <remarks>This member supports the .NET Framework

    /// infrastructure and is not intended

    /// to be used directly from your code.</remarks>

    protected MyType(System.Runtime.Serialization.SerializationInfo info, 
              System.Runtime.Serialization.StreamingContext context)
    {
        this.myField = ((int)(info.GetValue("myField", typeof(int))));
    }

    /// <summary>

    /// Populates a <see cref="System.Runtime.Serialization.
    ///                        SerializationInfo" />

    /// with the data needed to serialize the target object.

    /// </summary>

    /// <param name="info">The <see 
    /// cref="System.Runtime.Serialization.SerializationInfo" />

    /// to populate with data.</param>

    /// <param name="context">The destination (see <see 
    /// cref="System.Runtime.Serialization.StreamingContext" />)

    /// for this serialization.</param>

    /// <exception cref="System.ArgumentNullException">Thrown

    /// when the <paramref name="info" /> parameter is a null

    /// reference (Nothing in Visual Basic).</exception>

    [System.Security.Permissions.SecurityPermissionAttribute(
        System.Security.Permissions.SecurityAction.LinkDemand, 
        Flags=System.Security.Permissions.
              SecurityPermissionFlag.SerializationFormatter)]
    public virtual void GetObjectData(
           System.Runtime.Serialization.SerializationInfo 
           info, System.Runtime.Serialization.StreamingContext context)
    {
        if ((info == null))
        {
            throw new System.ArgumentNullException("info");
        }
        info.AddValue("myField", this.myField, typeof(int));
    }
}

The Singleton pattern

The Singleton pattern is a classic pattern which allows a class to only have one instance in the application. This implementation follows the best practices and is thread-safe. It also allows lazy-loading or pre-loading implementation. Documentation on the members generated can be controlled using the HasComments property.

In order to include this pattern in your code, your code should look like this:

nameSpace.Types.Add(new CodePatternSingleton("Foo", 
                                   LoadType.LazyLoad));

The code generated by above will be:

public class Foo
{
    private Foo()
    {
    }

    /// <summary>

    /// Gets the single instance of type <see cref="Foo" />.

    /// </summary>

    /// <value>The single instance of type <see cref="Foo" />.</value>

    public static Foo Instance
    {
        get
        {
            return InstanceContainer.Instance;
        }
    }

    class InstanceContainer
    {
        private static Foo m_Instance = new Foo();

        static InstanceContainer()
        {
        }

        private InstanceContainer()
        {
        }

        public static Foo Instance
        {
            get
            {
                return InstanceContainer.m_Instance;
            }
        }
    }
}

The Typed Collection pattern

The Typed Collection pattern is a woe on the way to completely strongly typed implementations. This is one of the most common type patterns, and also one of those patterns which can have 1001 different implementations. This implementation includes optional events (with the ability to silence them when loading data), a complete IList implementation and additional convenience constructors and methods, such as AddRange and ToArray.

In order to include this pattern in your code, your code should look like this:

nameSpace.Types.Add(new CodePatternTypedCollection(
                      typeof(int), CollectionEvents.All));

The code generated by above will be:

/// <summary>

/// Represents a collection of <see cref="Int32" /> elements.

/// </summary>

[System.SerializableAttribute()]
public class Int32Collection : System.Collections.CollectionBase
{
    /// <summary>

    /// See <see cref="IsInLoad" /> for information about this field.

    /// </summary>

    private int m_IsInLoad;
    
    /// <summary>

    /// Initializes a new instance

    /// of the <see cref="Int32Collection" /> class.

    /// </summary>

    public Int32Collection()
    {
    }
    
    /// <summary>

    /// Initializes a new instance of the

    /// <see cref="Int32Collection" /> class.

    /// </summary>

    /// <param name="values">A list of objects of type

    /// <see cref="Int32" /> to initialize

    /// the collection with.</param>

    public Int32Collection(params int[] values)
    {
        if ((values == null))
        {
            throw new System.ArgumentNullException("values");
        }
        this.InnerList.Capacity = values.Length;
        this.BeginLoad();
        try
        {
            this.AddRange(values);
        }
        finally
        {
            this.EndLoad();
        }
    }
    
    /// <summary>

    /// Initializes a new instance of the

    /// <see cref="Int32Collection" /> class.

    /// </summary>

    /// <param name="collection">An object of type

    /// <see cref="Int32Collection" /> containing

    /// objects to be copied into the new collection.</param>

    public Int32Collection(Int32Collection collection)
    {
        if ((collection == null))
        {
            throw new System.ArgumentNullException("collection");
        }
        this.InnerList.Capacity = collection.Count;
        this.BeginLoad();
        try
        {
            this.AddRange(collection);
        }
        finally
        {
            this.EndLoad();
        }
    }
    
    /// <summary>

    /// Gets or sets the <see cref="Int32" />

    /// at position <paramref name="index" />.

    /// </summary>

    /// <value>The <see cref="Int32" /> at position

    /// <paramref name="index" />.</value>

    /// <param name="index">The position

    /// of the <see cref="Int32" />.</param>

    public int this[int index]
    {
        get
        {
            return ((int)(this.List[index]));
        }
        set
        {
            this.List[index] = value;
        }
    }
    
    /// <summary>

    /// Gets an object that can be used

    /// to synchronize access to the collection.

    /// </summary>

    /// <value>An object that can be used to synchronize

    /// access to the collection.</value>

    public object SyncRoot
    {
        get
        {
            return this.List.SyncRoot;
        }
    }
    
    /// <summary>

    /// Occurs when the collection begins

    /// the process of removing all elements.

    /// </summary>

    /// <remarks>To indicate that clearing the collection

    /// is not possible, throw an exception

    /// from an attached method.</remarks>

    public event System.EventHandler Clearing;
    
    /// <summary>

    /// Occurs after the collection completes

    /// the process of removing all elements.

    /// </summary>

    public event System.EventHandler Cleared;
    
    /// <summary>

    /// Occurs when the collection begins

    /// the process of inserting an element.

    /// </summary>

    /// <remarks>To indicate that inserting this element is invalid,

    /// throw an exception from an attached method. To indicate

    /// that the element is simply invalid, use the

    /// <see cref="Validating" /> event.</remarks>

    public event EventHandler Inserting;
    
    /// <summary>

    /// Occurs after the collection completes

    /// the process of inserting an element.

    /// </summary>

    /// <remarks>To prevent the insertion from taking place,

    /// throw an exception from an attached method.</remarks>

    public event EventHandler Inserted;
    
    /// <summary>

    /// Occurs when the collection begins

    /// the process of removing an element.

    /// </summary>

    /// <remarks>To indicate that removing this element is invalid,

    /// throw an exception from an attached method. To indicate that

    /// the element is simply invalid, use the

    /// <see cref="Validating" /> event.</remarks>

    public event EventHandler Removing;
    
    /// <summary>

    /// Occurs after the collection completes

    /// the process of removing an element.

    /// </summary>

    /// <remarks>To prevent the removal from taking place,

    /// throw an exception from an attached method.</remarks>

    public event EventHandler Removed;
    
    /// <summary>

    /// Occurs when the collection begins the process

    /// of setting an element at a certain position.

    /// </summary>

    /// <remarks>To indicate that setting this element

    /// at this position is invalid, throw an exception from an attached

    /// method. To indicate that the element is simply invalid,

    /// use the <see cref="Validating" /> event.</remarks>

    public event SetEventHandler Setting;
    
    /// <summary>

    /// Occurs after the collection completes the process

    /// of setting an element at a certain position.

    /// </summary>

    /// <remarks>To prevent the settng action from taking

    /// place, throw an exception from an attached method.</remarks>

    public event SetEventHandler Set;
    
    /// <summary>

    /// Occurs when the collection asks for validation

    /// of an item that is to be added into it.

    /// </summary>

    /// <remarks>If the item is invalid,

    /// throw an exception from an attached method.

    /// Checks that already take place are that the value is not a null

    /// reference (Nothing in Visual Basic) and that it is of/derives

    /// from <see cref="Int32" />.</remarks>

    public event ValidationEventHandler Validating;
    
    /// <summary>

    /// Begins the Load process.

    /// </summary>

    public virtual void BeginLoad()
    {
        this.m_IsInLoad = (this.m_IsInLoad + 1);
    }
    
    /// <summary>

    /// Ends the Load process.

    /// </summary>

    public virtual void EndLoad()
    {
        if ((this.m_IsInLoad != 0))
        {
            this.m_IsInLoad = (this.m_IsInLoad - 1);
        }
    }
    
    /// <summary>

    /// Gets whether the Load process has begun.

    /// </summary>

    /// <value>Whether the Load process has begun.</value>

    protected bool IsInLoad()
    {
        return (this.m_IsInLoad != 0);
    }
    
    /// <summary>

    /// Inserts an element into the collection at the specified index.

    /// </summary>

    /// <param name="index">The zero-based index at which

    /// <paramref name="value" /> should be inserted.</param>

    /// <param name="value">The <see cref="Int32" /> to insert.</param>

    /// <exception cref="System.ArgumentOutOfRangeException">

    /// <paramref name="index" /> is less than zero or is greater

    /// than <see cref="System.Collections.CollectionBase.Count" />.

    /// </exception>

    public void Insert(int index, int value)
    {
        this.List.Insert(index, value);
    }
    
    /// <summary>

    /// Removes the first occurrence of a specific

    /// <see cref="Int32" /> from the collection.

    /// </summary>

    /// <param name="value">The <see cref="Int32" />

    /// to remove from the collection.</param>

    public void Remove(int value)
    {
        this.List.Remove(value);
    }
    
    /// <summary>

    /// Determines whether an element is in the collection.

    /// </summary>

    /// <param name="value">The <see cref="Int32" />

    /// to locate in the collection.</param>

    /// <returns>true if <paramref name="value" />

    /// is found in the collection; otherwise, false.</returns>

    public bool Contains(int value)
    {
        return this.List.Contains(value);
    }
    
    /// <summary>

    /// Searches for the specified <see cref="Int32" />

    /// and returns the zero-based index of the first

    /// occurrence within the entire collection.

    /// </summary>

    /// <param name="value">The <see cref="Int32" />

    /// to locate in the collection.</param>

    /// <returns>The zero-based index of the first occurrence

    /// of <paramref name="value" /> within the entire collection,

    /// if found; otherwise, -1.</returns>

    public int IndexOf(int value)
    {
        return this.List.IndexOf(value);
    }
    
    /// <summary>

    /// Adds an object to the end of the collection.

    /// </summary>

    /// <param name="value">The <see cref="Int32" />

    /// to be added to the end of the collection.</param>

    /// <returns>The collection index at which the

    /// <paramref name="value" /> has been added.</returns>

    public int Add(int value)
    {
        return this.List.Add(value);
    }
    
    /// <summary>

    /// Adds the elements of an array to the end of the collection.

    /// </summary>

    /// <param name="values">The array whose elements should be

    /// added to the end of the collection.</param>

    /// <exception cref="System.ArgumentNullException">

    /// <paramref name="values" /> is a null reference

    /// (Nothing in Visual Basic).</exception>

    public void AddRange(int[] values)
    {
        if ((values == null))
        {
            throw new System.ArgumentNullException("values");
        }
        System.Collections.IEnumerator enumerator0 = 
           ((System.Collections.IEnumerable)(values)).GetEnumerator();
        try
        {
            for (
                ; (enumerator0.MoveNext() == true); 
                )
            {
                int element0 = ((int)(enumerator0.Current));
                this.List.Add(element0);
            }
        }
        finally
        {
            if (((enumerator0 != null) 
                && enumerator0.GetType().IsInstanceOfType(
                   typeof(System.IDisposable))))
            {
                ((System.IDisposable)(enumerator0)).Dispose();
            }
        }
    }
    
    /// <summary>

    /// Adds the elements of a collection to the end of the collection.

    /// </summary>

    /// <param name="collection">The collection whose elements

    /// should be added to the end of the collection.</param>

    /// <exception cref="System.ArgumentNullException">

    /// <paramref name="collection" /> is a null reference

    /// (Nothing in Visual Basic).</exception>

    public void AddRange(Int32Collection collection)
    {
        if ((collection == null))
        {
            throw new System.ArgumentNullException("collection");
        }
        System.Collections.IEnumerator enumerator1 = 
           ((System.Collections.IEnumerable)
            (collection.InnerList)).GetEnumerator();
        try
        {
            for (
                ; (enumerator1.MoveNext() == true); 
                )
            {
                int element1 = ((int)(enumerator1.Current));
                this.List.Add(element1);
            }
        }
        finally
        {
            if (((enumerator1 != null) 
                && enumerator1.GetType().IsInstanceOfType(
                   typeof(System.IDisposable))))
            {
                ((System.IDisposable)(enumerator1)).Dispose();
            }
        }
    }
    
    /// <summary>

    /// Copies the entire collection to a compatible one-dimensional

    /// <see cref="System.Array" />, starting at the specified

    /// <paramref name="index" /> of the target array.

    /// </summary>

    /// <param name="array">The one-dimensional

    /// <see cref="System.Array" />

    /// that is the destination of the elements copied from collection.

    /// The <see cref="System.Array" /> must

    /// have zero-based indexing.</param>

    /// <param name="index">The zero-based index in <paramref
    /// name="array" /> at which copying begins.</param>

    /// <exception cref="System.ArgumentNullException"><paramref
    /// name="array" /> is a null reference

    /// (Nothing in Visual Basic).</exception>

    /// <exception cref="System.ArgumentOutOfRangeException">

    /// <paramref name="index" /> is less than zero.</exception>

    /// <exception cref="System.ArgumentException"><paramref
    /// name="array" /> is multidimensional.</exception>

    /// <exception cref="System.ArgumentException">

    /// <paramref name="index" />

    /// is equal to or greater than the length

    /// of <paramref name="array" />.</exception>

    /// <exception cref="System.ArgumentException">The number

    /// of elements in the source collection

    /// is greater than the available space

    /// from <paramref name="index" /> to the end of the destination

    /// <paramref name="array" />.</exception>

    /// <remarks>The specified array's elements must be of type

    /// <see cref="Int32" /> or any of its derivatives.</remarks>

    public void CopyTo(System.Array array, int index)
    {
        this.List.CopyTo(array, index);
    }
    
    /// <summary>

    /// Copies the elements of the collection

    /// to a new <see cref="Int32" /> array.

    /// </summary>

    /// <returns>An array of <see cref="Int32" /> containing

    /// copies of the elements of the collection.</returns>

    public int[] ToArray()
    {
        return ((int[])(this.InnerList.ToArray(typeof(Int32))));
    }
    
    /// <summary>

    /// Raises the <see cref="Clearing" /> event.

    /// </summary>

    protected override void OnClear()
    {
        if (((this.IsInLoad() == false) 
            && (this.Clearing != null)))
        {
            this.Clearing(this, System.EventArgs.Empty);
        }
    }
    
    /// <summary>

    /// Raises the <see cref="Cleared" /> event.

    /// </summary>

    protected override void OnClearComplete()
    {
        if (((this.IsInLoad() == false) 
            && (this.Cleared != null)))
        {
            this.Cleared(this, System.EventArgs.Empty);
        }
    }
    
    /// <summary>

    /// Raises the <see cref="Inserting" /> event.

    /// </summary>

    /// <param name="index">The zero-based index at which

    /// to insert <paramref name="value" />.</param>

    /// <param name="value">The new value of the element

    /// at <paramref name="index" />.</param>

    protected override void OnInsert(int index, object value)
    {
        if (((this.IsInLoad() == false) 
            && (this.Inserting != null)))
        {
            this.Inserting(this, new EventArgs(index, ((int)(value))));
        }
    }
    
    /// <summary>

    /// Raises the <see cref="Inserted" /> event.

    /// </summary>

    /// <param name="index">The zero-based index at which

    /// to insert <paramref name="value" />.</param>

    /// <param name="value">The new value of the element

    /// at <paramref name="index" />.</param>

    protected override void OnInsertComplete(int index, object value)
    {
        if (((this.IsInLoad() == false) 
            && (this.Inserted != null)))
        {
            this.Inserted(this, new EventArgs(index, ((int)(value))));
        }
    }
    
    /// <summary>

    /// Raises the <see cref="Removing" /> event.

    /// </summary>

    /// <param name="index">The zero-based index at which

    /// <paramref name="value" /> can be found.</param>

    /// <param name="value">The value of the element to remove

    /// from <paramref name="index" />.</param>

    protected override void OnRemove(int index, object value)
    {
        if (((this.IsInLoad() == false) 
            && (this.Removing != null)))
        {
            this.Removing(this, new EventArgs(index, 
                         ((int)(value))));
        }
    }
    
    /// <summary>

    /// Raises the <see cref="Removed" /> event.

    /// </summary>

    /// <param name="index">The zero-based index at which

    /// <paramref name="value" /> can be found.</param>

    /// <param name="value">The value of the element

    /// to remove from <paramref name="index" />.</param>

    protected override void OnRemoveComplete(int index, object value)
    {
        if (((this.IsInLoad() == false) 
            && (this.Removed != null)))
        {
            this.Removed(this, new EventArgs(index, 
                        ((int)(value))));
        }
    }
    
    /// <summary>

    /// Raises the <see cref="Setting" /> event.

    /// </summary>

    /// <param name="index">The zero-based index at which

    /// <paramref name="oldValue" /> can be found.</param>

    /// <param name="oldValue">The value to replace

    /// with <paramref name="newValue" />.</param>

    /// <param name="newValue">The new value of the

    /// element at <paramref name="index" />.</param>

    protected override void OnSet(int index, 
              object oldValue, object newValue)
    {
        if (((this.IsInLoad() == false) 
            && (this.Setting != null)))
        {
            this.Setting(this, new SetEventArgs(index, 
                        ((int)(oldValue)), ((int)(newValue))));
        }
    }
    
    /// <summary>

    /// Raises the <see cref="Set" /> event.

    /// </summary>

    /// <param name="index">The zero-based index at which

    /// <paramref name="oldValue" /> can be found.</param>

    /// <param name="oldValue">The value to replace

    /// with <paramref name="newValue" />.</param>

    /// <param name="newValue">The new value of the element

    /// at <paramref name="index" />.</param>

    protected override void OnSetComplete(int index, 
              object oldValue, object newValue)
    {
        if (((this.IsInLoad() == false) 
            && (this.Set != null)))
        {
            this.Set(this, new SetEventArgs(index, 
                    ((int)(oldValue)), ((int)(newValue))));
        }
    }
    
    /// <summary>

    /// Raises the <see cref="Validating" /> event.

    /// </summary>

    /// <param name="value">The object to validate.</param>

    protected override void OnValidate(object value)
    {
        base.OnValidate(value);
        if ((value.GetType().IsInstanceOfType(typeof(int)) == false))
        {
            throw new System.ArgumentException(
                  string.Format("The argument" + 
                  " value must be of type {0}.", 
                  typeof(int).FullName), "value");
        }
        if (((this.IsInLoad() == false) 
            && (this.Validating != null)))
        {
            this.Validating(this, 
                new ValidationEventArgs(((int)(value))));
        }
    }
    
    /// <summary>

    /// Represents a method that takes a <see cref="System.Object" />

    /// and <see cref="EventArgs" />.

    /// </summary>

    /// <param name="sender">The event's originating object.</param>

    /// <param name="e">The event's arguments.</param>

    public delegate void EventHandler(object sender, EventArgs e);
    
    /// <summary>

    /// Contains the arguments for events based

    /// on the <see cref="EventHandler" /> delegate.

    /// </summary>

    public class EventArgs : System.EventArgs
    {
        /// <summary>

        /// Value for the property <see cref="Index" />.

        /// </summary>

        private int m_Index;
        
        /// <summary>

        /// Value for the property <see cref="Value" />.

        /// </summary>

        private int m_Value;
        
        /// <summary>

        /// Initializes a new instance

        /// of the <see cref="EventArgs" /> class.

        /// </summary>

        /// <param name="Index">The index of the value.</param>

        /// <param name="Value">The value raised by the event.</param>

        public EventArgs(int Index, int Value)
        {
            this.m_Index = Index;
            this.m_Value = Value;
        }
        
        /// <summary>

        /// Gets the index of the value.

        /// </summary>

        /// <value>The index of the value.</value>

        public virtual int Index
        {
            get
            {
                return this.m_Index;
            }
        }
        
        /// <summary>

        /// Gets the value raised by the event.

        /// </summary>

        /// <value>The value raised by the event.</value>

        public virtual int Value
        {
            get
            {
                return this.m_Value;
            }
        }
    }
    
    /// <summary>

    /// Represents a method that takes a

    /// <see cref="System.Object" />

    /// and <see cref="SetEventArgs" />.

    /// </summary>

    /// <param name="sender">The event's originating object.</param>

    /// <param name="e">The event's arguments.</param>

    public delegate void SetEventHandler(object sender, 
                                         SetEventArgs e);
    
    /// <summary>

    /// Contains the arguments for events based on the

    /// <see cref="SetEventHandler" /> delegate.

    /// </summary>

    public class SetEventArgs : System.EventArgs
    {
        /// <summary>

        /// Value for the property <see cref="Index" />.

        /// </summary>

        private int m_Index;
        
        /// <summary>

        /// Value for the property <see cref="OldValue" />.

        /// </summary>

        private int m_OldValue;
        
        /// <summary>

        /// Value for the property <see cref="NewValue" />.

        /// </summary>

        private int m_NewValue;
        
        /// <summary>

        /// Initializes a new instance of the

        /// <see cref="SetEventArgs" /> class.

        /// </summary>

        /// <param name="Index">The zero-based index

        /// at which oldValue can be found.</param>

        /// <param name="OldValue">The value

        /// to replace with newValue.</param>

        /// <param name="NewValue">The new value

        /// of the element at index.</param>

        public SetEventArgs(int Index, int OldValue, int NewValue)
        {
            this.m_Index = Index;
            this.m_OldValue = OldValue;
            this.m_NewValue = NewValue;
        }
        
        /// <summary>

        /// Gets the zero-based index at which oldValue can be found.

        /// </summary>

        /// <value>The zero-based index at which

        /// oldValue can be found.</value>

        public virtual int Index
        {
            get
            {
                return this.m_Index;
            }
        }
        
        /// <summary>

        /// Gets the value to replace with newValue.

        /// </summary>

        /// <value>The value to replace with newValue.</value>

        public virtual int OldValue
        {
            get
            {
                return this.m_OldValue;
            }
        }
        
        /// <summary>

        /// Gets the new value of the element at index.

        /// </summary>

        /// <value>The new value of the element at index.</value>

        public virtual int NewValue
        {
            get
            {
                return this.m_NewValue;
            }
        }
    }
    
    /// <summary>

    /// Represents a method that takes a <see cref="System.Object" />

    /// and <see cref="ValidationEventArgs" />.

    /// </summary>

    /// <param name="sender">The event's originating object.</param>

    /// <param name="e">The event's arguments.</param>

    public delegate void ValidationEventHandler(object sender, 
                                        ValidationEventArgs e);
    
    /// <summary>

    /// Contains the arguments for events based

    /// on the <see cref="ValidationEventHandler" /> delegate.

    /// </summary>

    public class ValidationEventArgs : System.EventArgs
    {
        /// <summary>

        /// Value for the property <see cref="Value" />.

        /// </summary>

        private int m_Value;
        
        /// <summary>

        /// Initializes a new instance of the

        /// <see cref="ValidationEventArgs" /> class.

        /// </summary>

        /// <param name="Value">The value to be validated.</param>

        public ValidationEventArgs(int Value)
        {
            this.m_Value = Value;
        }
        
        /// <summary>

        /// Gets the value to be validated.

        /// </summary>

        /// <value>The value to be validated.</value>

        public virtual int Value
        {
            get
            {
                return this.m_Value;
            }
        }
    }
}

Please note that a bug in the .NET Frameworks up to (and not including) 2.0 does not allow for creation of parameter arrays, which means that the pattern is incomplete when used with these versions.

Unary Operator patterns

No unary operators are built into CodeDom. This pattern extends the normal CodeBinaryOperatorExpression to add more operators. Currently supported operator/s: BooleanNot, BooleanIsTrue, IsNull, NotNull.

In order to include this pattern in your code, your code should look like this:

method.Statements.Add(
    new CodeConditionStatement(
        new CodePatternBinaryOperatorExpression(
            CodePatternUnaryOperatorType.BooleanNot,
            new CodeVariableReferenceExpression("bool1"))
        /* , Contained statements */));

The code generated by above will be:

if (bool1 == false)
{
    // Contained statements...

}

The Using pattern

The Using pattern is built into C#, but is not native to IL. The pattern uses a resource that implements the System.IDisposable interface, then releases it.

In order to include this pattern in your code, your code should look like this:

method.Statements.AddRange(new CodePatternUsing(
    new CodeVariableDeclarationStatement(
                typeof(System.Drawing.Image), "image"),
    ResourceType.ReferenceType
    /* , Contained statements... */));

The code generated by above will be:

System.Drawing.Image image;

try
{
    // Contained statements...

}
finally
{
    if ((image != null))
    {
        ((System.IDisposable)(image)).Dispose();
    }
}

XML Comment patterns

XML comments are the standard method of writing member comments which are descriptive and easy to parse using tool such as NDoc. The currently supported tags and their class equivalents are:

Also, there are several templates: CommentsForConstructor, CommentsForMethod, CommentsForProperty and CommentsForIndexer.

On a side note, Sandcastle has been released by Microsoft, but it has not yet been finalized. Once it is, classes will be added to support the more advanced features it offers.

History

Creative Commons License
This work is licensed under a Creative Commons Attribution 2.5 License
(Can copy, distribute, derive, use commercially; Must attribute to author)

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralBug in CodePatternLock ?
zebadiah81
14:46 31 Oct '07  

Hey, I'm not sure if this is the right place to put this, but there seems to be a bug in the CodePatternLock - the "statements in the lock block" are not added.

Your Code:

CodeTryCatchFinallyStatement tryCatch = new CodeTryCatchFinallyStatement();

tryCatch.FinallyStatements.Add(exitMonitor);


Should Be:

CodeTryCatchFinallyStatement tryCatch = new CodeTryCatchFinallyStatement();

tryCatch.TryStatements.AddRange(statements);
tryCatch.FinallyStatements.Add(exitMonitor);

Love your work.


Ben
GeneralUnary Pattern
Gilesb
6:01 4 Feb '07  
The unary pattern is useless, there are no "Unary" operators such as IsNull or IsNotNull in any language I know of.

Consider the following example in VB:

Dim o as Object
If (o IsNot Nothing) Then
End If

the IsNot operator is a binary operator.

What I really need is a real unary operator such as 'subtract' or 'add' e.g. in VB:

i = 5 + (-j)

There is no way todo this in CodeDom unless I have missed something.
AnswerRe: Unary Pattern
Omer van Kloeten
6:54 4 Feb '07  
C/C++ allows you to check for null just by using 'if (!somePtr)' and that's where I got that from.

The negative operator ('-j') is doable and I'll add it to the next release - thanks Smile

-------
Programming is life,
The rest is mere details.

Omer van Kloeten

GeneralRe: Unary Pattern
Gilesb
1:34 7 Feb '07  
I realised just after I made the post that the unary operator can be simulated by a binary operator with left had operand of zero.


i = (-j) ==> i = (0 - j)

Well that works for numbers.

Not sure about (-True) shouldn't that return False?
My Immediate window in VS2005 seems to disagree.

GeneralCan It be done with Codedom?
mbkasi
15:55 8 Nov '06  
Hai Can I generate following code with codedom?

Public Property ResourceKey() As String
_
Get
CanReadProperty(True)
Return mResourceKey
End Get
_
Set(ByVal value As String)
CanWriteProperty(True)
If mResourceKey <> value Then
mResourceKey = value.Trim
PropertyChanged()
End If
End Set
End Property

Thanks
Visu
AnswerRe: Can It be done with Codedom?
Omer van Kloeten
1:15 9 Nov '06  
Certainly.

If you want to learn about CodeDom, you can visit my articles here:
http://weblogs.asp.net/okloeten/category/4698.aspx

-------
Programming is life,
The rest is mere details.

Omer van Kloeten

Generalsuggestion
System.Object
3:51 17 May '06  
if((myArgument.GetType().IsInstanceOfType(typeof(int)) == false))

can be replaced by

if(myArgument is int)

by the way, i am missing patterns for codedom to assert that a string may not be empty and that an enum-value must be defined (Enum.IsDefined)
AnswerRe: suggestion
Omer van Kloeten
9:13 17 May '06  
Since the 'is' expression is not part of CodeDom, the pattern you mention comes to replace it. It does look less readable, but at least it gets the job done.

Good idea about the assertions, though. I'll add them to the next version (1.7). Thank you Smile

-------
Programming is life,
The rest is mere details.

Omer van Kloeten
GeneralRe: suggestion
System.Object
9:34 17 May '06  
you are right! unbelievable that codedom doesnt support this construct. what do you think about a custom EventArgs pattern like this:

class XXXEventArgs : EventArgs
{
XXX m_XXX;

public XXXEventArgs(XXX data)
{
m_XXX = data;
}

public XXX XXX
{
get {return m_XXX;}
}
}

i wrote a code snippet for visual studio like this
GeneralRe: suggestion
Omer van Kloeten
9:46 17 May '06  
This already exists inside the Delegate pattern. You can simply choose to only add that class if you create a CodePatternDelegate and use its EventArgs property as a refernce to that type.

-------
Programming is life,
The rest is mere details.

Omer van Kloeten
GeneralRe: suggestion
Efran Cobisi
7:07 10 Oct '06  
Well, this is not correct.
If the argument you are testing the type of is null an exception would be thrown.

Actually IL DOES support the "is" c# keyword via the isinst opcode but afaik there is no support for that opcode in the CodeDom.

HTH

Efran Cobisi, cobisi.com
AnswerRe: suggestion
Omer van Kloeten
8:04 10 Oct '06  
Yes, that's true, but since checking value types for equality to null is not allowed in some langauges, I have left the check for the user. You can use the unary NotNull operator pattern to check for null.

And yes, as stated in TFA, is is supported by the CLR, but not implemented in CodeDom. Smile


Programming is life,
The rest is mere details.

Omer van Kloeten

Generalnullable property
jonavi
13:10 8 May '06  
how would you create a nullable field and property type?
so something like int? or string?

AnswerRe: nullable property
Omer van Kloeten
18:41 8 May '06  
I was thinking on creating the same mechanism as one would have in Typed DataSets, but only if nothing better comes up:
public int Foo { get; set; }
public void SetFooNull();
public bool IsFooNull { get; }

This will probably be out in the next version.

-------
Programming is life,
The rest is mere details.

Omer van Kloeten
Generalspectacular
jonavi
11:07 8 May '06  
Every day i have played with your samples and the code dom, i love it more and more
i am making dal generators, and object generators based on xml templates.
it's awsome, and our code helps me understand it all and how to accomplish each task ive come up with.
great!!!!
GeneralRe: spectacular
Omer van Kloeten
18:53 8 May '06  
Thank you, I really appreciate it.

-------
Programming is life,
The rest is mere details.

Omer van Kloeten
GeneralAdding Region
vbinfo
23:11 15 Jan '06  
Hi,
First of all THANKS for providing such a good article.
I am working on vs 2005 and I am loading fields programmatically from a database to generate properties and I cannot seem to make them go into a region for neatness.What about a region Pattern?or do you have a quick example how to put stuff into region?

Thanks A lot
vbinfo@devnet247.com
AnswerRe: Adding Region
Omer van Kloeten
7:22 16 Jan '06  
I'm glad you're enjoying the article. The next update will feature many new useful improvements.

If you want to add a region directive when using Visual Studio 2005 (i.e. .NET 2.0), use the CodeRegionDirective Class that has just been added to the framework.

If you're using an earlier version of the .NET Framework, you can not create region directives, because the types in a namespace / members in a type are not generated according to the order of insertion into the collection. Also, the known workaround of using a CodeSnippet type of object for generating this type of statement (that is, putting a region block inside a method/property), is blatant disregard for the autonomy of CodeDOM from languages.

Programming is life,
The rest is mere details.

Omer van Kloeten
GeneralRe: Adding Region
vbinfo
7:46 16 Jan '06  
Thanks for your reply.
I will try to implement the CodeRegionDirective Class and see if i can make it work.When are planning the next update?

thanks again

Thanks A lot
vbinfo@devnet247.com
AnswerRe: Adding Region
Omer van Kloeten
8:22 16 Jan '06  
It depends on the amount of free time on my hands.
In the next release (1.3), I'm planning to add, among other things, a custom attribute pattern.

Programming is life,
The rest is mere details.

Omer van Kloeten
GeneralExcellent!
Alexey A. Popov
22:48 17 Nov '05  
You idea to create a library of ready-to-use CodeDom statements is absolutely outstanding! It's like NAnt.Contibute for the CodeDom. Why don't you create a kind of a wiki with the library and collection of such statements?
AnswerRe: Excellent!
Omer van Kloeten
1:00 18 Nov '05  
I was thinking about splitting it up into several different articles, each one with extentions to complement a specific language, but I decided it best to leave it like this.

I would put this on sourceforge, but I haven't the power to start learning cvs or svn Smile

Programming is life,
The rest is mere details.

Omer van Kloeten
GeneralDumb question
smesser
6:39 17 Nov '05  
I have recently been seeing the term CodeDom alot lately and with a little research that I
have done I don't understand this term.

Could you expain it?
GeneralRe: Dumb question
Tony Snearly
7:52 17 Nov '05  
I didn't know what was meant by CodeDom either. But I found this great article that explains the technology and its' use.

http://www.15seconds.com/issue/020917.htm
AnswerRe: Dumb question
Omer van Kloeten
9:34 17 Nov '05  
I have a set of articles on my blogs that could give you a good introduction to CodeDom.
http://weblogs.asp.net/okloeten/category/4698.aspx

Enjoy Smile

Programming is life,
The rest is mere details.

Omer van Kloeten


Last Updated 31 Oct 2006 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010