Table of contents
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.
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");
}
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)]
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:
private MyMethodAsyncCallback m_MyMethodCallback;
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);
}
public System.IAsyncResult BeginMyMethod(int foo)
{
return this.BeginMyMethod(foo, null);
}
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);
}
public delegate void MyMethodAsyncCallback(int foo);
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:
private int m_IsInInit;
public virtual void BeginInit()
{
this.m_IsInInit = (this.m_IsInInit + 1);
}
public virtual void EndInit()
{
if ((this.m_IsInInit != 0))
{
this.m_IsInInit = (this.m_IsInInit - 1);
}
}
protected bool IsInInit()
{
return (this.m_IsInInit != 0);
}
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"))
));
The code generated by above will be:
if (((bool1 == true) && (bool2 == false)) ||
((bool1 == false) && (bool2 == true)))
{
}
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.
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);
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());
The code generated by above will be:
System.Windows.Forms.Cursor cursor0 = this.Cursor;
try
{
this.Cursor = System.Windows.Forms.Cursors.WaitCursor;
}
finally
{
this.Cursor = cursor0;
}
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
{
private int m_MetaData;
public CoolMetaDataAttribute()
{
}
public CoolMetaDataAttribute(int MetaData)
{
this.m_MetaData = MetaData;
}
public int MetaData
{
get
{
return this.m_MetaData;
}
}
}
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
{
private int m_Bar;
public FooException(int Bar)
{
this.m_Bar = Bar;
}
public FooException(int Bar, string message) :
base(message)
{
this.m_Bar = Bar;
}
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))));
}
public FooException(int Bar, string message,
System.Exception innerException) :
base(message, innerException)
{
this.m_Bar = Bar;
}
public int Bar
{
get
{
return this.m_Bar;
}
}
[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, 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:
public delegate void ItemChangedEventHandler(object sender,
ItemChangedEventArgs e);
public class ItemChangedEventArgs : System.EventArgs
{
private int m_OldValue;
private int m_NewValue;
public ItemChangedEventArgs(int OldValue, int NewValue)
{
this.m_OldValue = OldValue;
this.m_NewValue = NewValue;
}
public virtual int OldValue
{
get
{
return this.m_OldValue;
}
}
public virtual int NewValue
{
get
{
return this.m_NewValue;
}
}
}
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
{
public void Dispose()
{
this.Dispose(true);
System.GC.SuppressFinalize(this);
}
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 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;
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 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 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")
));
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));
}
}
finally
{
if (((enumerator0 != null) &&
enumerator0.GetType().IsInstanceOfType(
typeof(System.IDisposable))))
{
((System.IDisposable)(enumerator0)).Dispose();
}
}
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 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 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")
));
The code generated by above will be:
object lockCachedExpr0 = this.SyncRoot;
System.Threading.Monitor.Enter(lockCachedExpr0);
try
{
}
finally
{
System.Threading.Monitor.Exit(lockCachedExpr0);
}
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;
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;
}
}
public bool IsValueNull
{
get
{
return this.m_IsValueNull;
}
}
public void SetValueNull()
{
this.m_IsValueNull = true;
}
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:
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));
}
}
}
public event MyValueChangedEventHandler MyValueChanged;
protected virtual void OnMyValueChanged(MyValueChangedEventArgs e)
{
if ((this.MyValueChanged != null))
{
this.MyValueChanged(this, e);
}
}
public delegate void MyValueChangedEventHandler(object sender,
MyValueChangedEventArgs e);
public class MyValueChangedEventArgs : System.EventArgs
{
private int m_OldValue;
private int m_NewValue;
public MyValueChangedEventArgs(int OldValue, int NewValue)
{
this.m_OldValue = OldValue;
this.m_NewValue = NewValue;
}
public virtual int OldValue
{
get
{
return this.m_OldValue;
}
}
public virtual int NewValue
{
get
{
return this.m_NewValue;
}
}
}
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;
protected MyType(System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
{
this.myField = ((int)(info.GetValue("myField", typeof(int))));
}
[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 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()
{
}
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 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:
[System.SerializableAttribute()]
public class Int32Collection : System.Collections.CollectionBase
{
private int m_IsInLoad;
public Int32Collection()
{
}
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();
}
}
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();
}
}
public int this[int index]
{
get
{
return ((int)(this.List[index]));
}
set
{
this.List[index] = value;
}
}
public object SyncRoot
{
get
{
return this.List.SyncRoot;
}
}
public event System.EventHandler Clearing;
public event System.EventHandler Cleared;
public event EventHandler Inserting;
public event EventHandler Inserted;
public event EventHandler Removing;
public event EventHandler Removed;
public event SetEventHandler Setting;
public event SetEventHandler Set;
public event ValidationEventHandler Validating;
public virtual void BeginLoad()
{
this.m_IsInLoad = (this.m_IsInLoad + 1);
}
public virtual void EndLoad()
{
if ((this.m_IsInLoad != 0))
{
this.m_IsInLoad = (this.m_IsInLoad - 1);
}
}
protected bool IsInLoad()
{
return (this.m_IsInLoad != 0);
}
public void Insert(int index, int value)
{
this.List.Insert(index, value);
}
public void Remove(int value)
{
this.List.Remove(value);
}
public bool Contains(int value)
{
return this.List.Contains(value);
}
public int IndexOf(int value)
{
return this.List.IndexOf(value);
}
public int Add(int value)
{
return this.List.Add(value);
}
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();
}
}
}
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();
}
}
}
public void CopyTo(System.Array array, int index)
{
this.List.CopyTo(array, index);
}
public int[] ToArray()
{
return ((int[])(this.InnerList.ToArray(typeof(Int32))));
}
protected override void OnClear()
{
if (((this.IsInLoad() == false)
&& (this.Clearing != null)))
{
this.Clearing(this, System.EventArgs.Empty);
}
}
protected override void OnClearComplete()
{
if (((this.IsInLoad() == false)
&& (this.Cleared != null)))
{
this.Cleared(this, System.EventArgs.Empty);
}
}
protected override void OnInsert(int index, object value)
{
if (((this.IsInLoad() == false)
&& (this.Inserting != null)))
{
this.Inserting(this, new EventArgs(index, ((int)(value))));
}
}
protected override void OnInsertComplete(int index, object value)
{
if (((this.IsInLoad() == false)
&& (this.Inserted != null)))
{
this.Inserted(this, new EventArgs(index, ((int)(value))));
}
}
protected override void OnRemove(int index, object value)
{
if (((this.IsInLoad() == false)
&& (this.Removing != null)))
{
this.Removing(this, new EventArgs(index,
((int)(value))));
}
}
protected override void OnRemoveComplete(int index, object value)
{
if (((this.IsInLoad() == false)
&& (this.Removed != null)))
{
this.Removed(this, new EventArgs(index,
((int)(value))));
}
}
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))));
}
}
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))));
}
}
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))));
}
}
public delegate void EventHandler(object sender, EventArgs e);
public class EventArgs : System.EventArgs
{
private int m_Index;
private int m_Value;
public EventArgs(int Index, int Value)
{
this.m_Index = Index;
this.m_Value = Value;
}
public virtual int Index
{
get
{
return this.m_Index;
}
}
public virtual int Value
{
get
{
return this.m_Value;
}
}
}
public delegate void SetEventHandler(object sender,
SetEventArgs e);
public class SetEventArgs : System.EventArgs
{
private int m_Index;
private int m_OldValue;
private int m_NewValue;
public SetEventArgs(int Index, int OldValue, int NewValue)
{
this.m_Index = Index;
this.m_OldValue = OldValue;
this.m_NewValue = NewValue;
}
public virtual int Index
{
get
{
return this.m_Index;
}
}
public virtual int OldValue
{
get
{
return this.m_OldValue;
}
}
public virtual int NewValue
{
get
{
return this.m_NewValue;
}
}
}
public delegate void ValidationEventHandler(object sender,
ValidationEventArgs e);
public class ValidationEventArgs : System.EventArgs
{
private int m_Value;
public ValidationEventArgs(int Value)
{
this.m_Value = 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.
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"))
));
The code generated by above will be:
if (bool1 == false)
{
}
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
));
The code generated by above will be:
System.Drawing.Image image;
try
{
}
finally
{
if ((image != null))
{
((System.IDisposable)(image)).Dispose();
}
}
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:
- <summary> -
SummaryStatements
.
- <c> -
TextAsCodeExpression
.
- <code> -
MultilineTextAsCodeStatements
.
- <example> -
ExampleStatements
.
- <exception> -
ExceptionStatements
.
- <list> -
ListStatements
.
- <para> -
ParagraphExpression
.
- <param> -
ParameterStatements
.
- <paramref> -
ParameterReferenceExpression
.
- <remarks> -
RemarksStatements
.
- <returns> -
ReturnsStatements
.
- <see> -
SeeExpression
.
- <seealso> -
SeeAlsoStatements
.
- <value> -
ValueStatements
.
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.
- 2006-10-31 - Version 1.8.
- The Code Access Security Decorator Patterns have been added.
- The Assembly Information Pattern has been added.
- Security demand added to
GetObjectData
in the Serializable Type Pattern.
- XML Comment Patterns moved to the
.Xml
namespace and had their CodeXmlComment
prefix removed (too long).
- Binaries now target .NET 2.0 instead of .NET 1.1, but they are mostly still backwards compatible.
- 2006-09-23: Version 1.7.
- The Nullable Value Type Property Pattern has been added.
- The
Enum.IsDefined
and String.IsNullOrEmpty
assertions have been added.
- The Serializable Type Pattern has been added.
- The Disposable Type Pattern is now a part of
CodePatternTypeDeclaration
.
- 2006-04-29: Version 1.6.
- The Asynchronous Operation Pattern has been added.
- The Disposable Type Pattern has been added.
- The XML Comment Patterns have been added.
- Automatic documentation of the Begin/End Process, Custom Attribute, Custom Exception, Delegate, Event, Observer, Singleton, and Typed Collection patterns.
- The Unary Operators
IsNull
and NotNull
have been added.
- You can now access each flag's
CodeMemberField
in the Flags Pattern.
- The Singleton Pattern (Lazy Load) no longer publicly exposes the internally used class
InstanceContainer
.
- The Typed Collection Pattern's
ToArray
method has been fixed.
- The work is now licensed under the Creative Commons Attribution 2.5 License. You can copy, freely distribute, derive and even use the code in a commercial product, but you must attribute it to the author.
- 2006-03-31: Version 1.5.
- The Typed Collection pattern has been added.
- The Argument Assertion patterns have been added.
- Assembly and all types are now
CLSCompliant
.
- All types are now marked as
Serializable
.
- The Custom Attribute pattern now produces sealed attributes, to increase the efficiency of generated code.
- Several overload additions and bug fixes.
- 2006-02-10: Version 1.4.
- Compatible with generation for Visual Basic.
- Custom Exception pattern altered to take
CodeParameterDeclarationExpressions
instead of CodePatternGetFields
.
- The Event pattern now has an overload that takes a delegate type (and deduces the parameters and the return type).
- The For Each pattern now works according to the C# specifications.
- Several bug fixes.
- 2006-01-28: Version 1.3.
- Assembly renamed to DotNetZen.CodeDom.Patterns.
- The Custom Attribute pattern has been added.
- The Custom Exception pattern has been added.
- 2006-01-13: Version 1.2.
- Binary and unary operator patterns have been added.
- Compound assignment patterns have been added.
- 2005-11-11: Version 1.1.
- The Cursor Lock pattern now changes the cursor back to its original icon, rather than
Cursors.Default
.
- The For Each pattern has been added.
- The Is Instance Of pattern has been added.
- Boolean flags for scope are now implemented using the
Scope
enumeration.
- Boolean flags for the resource type on the Using pattern are now implemented using the
ResourceType
enumeration.
- Boolean flags for the load type on the Singleton pattern are now implemented using the
LoadType
enumeration.
- 2005-10-30: Initial release.
This work is licensed under a Creative Commons Attribution 2.5 License
(Can copy, distribute, derive, use commercially; Must attribute to author)