As per the definition above, the receiving object in our
example is an instance of the MyCustomCollection class, so we should derive it
from MarshalByRefObject. To make it act as it is also inheriting from System.Collections.ArrayList,
we will create a class called MyCustomCollectionSlave that inherits from
System.Collections.ArrayList.
MyCustomCollectionSlave will act as an object delegate to
MyCustomCollection (MyCustomCollectionSlave was not called MyCustomCollectionDelegate
to avoid confusion with the .NET System.Delegate type).
Now we need to inject (or "inherit") the behaviors
of MyCustomCollectionSlave into MyCustomCollection. This why we define a field
within MyCustomCollection called InnerList of type MyCustomCollectionSlave and
we write dumb entries for all methods of MyCustomCollectionSlave in MyCustomCollection.
These methods will only be responsible for forwarding calls to the MyCustomCollectionSlave
corresponding methods. The following listings make things easier to understand.
Listing 1
[C#]
//This class plays the role of a delegate
internal class MyCustomCollectionSlave : System.Collections.ArrayList
{
#region "Methods"
public object GetSomething() {
//Write some code here
}
#endregion
}
public class MyCustomCollection : System.MarshalByRefObject
{
#region "Fields"
private MyCustomCollectionSlave _InnerList;
#endregion
#region "Properties"
//Through this property, all delegation is done.
private MyCustomCollectionSlave InnerList {
get {
return this._InnerList;
}
}
//The properties below help delegating ArrayList's built-in properties.
public int Count {
get {
return this.InnerList.Count;
}
}
public bool IsSynchronized {
get {
return this.InnerList.IsSynchronized;
}
}
public object SyncRoot {
get {
return this.InnerList.SyncRoot;
}
}
public bool IsFixedSize {
get {
return this.InnerList.IsFixedSize;
}
}
public bool IsReadOnly {
get {
return this.InnerList.IsReadOnly;
}
}
public object this[int index] {
get {
return this.InnerList[index];
}
set {
this.InnerList[index] = value;
}
}
#endregion
#region "Constructors"
public MyCustomCollection() {
this._InnerList = new MyCustomCollectionSlave();
}
#endregion
#region "Methods"
//This method simply forwards calls to the GetSomething() method in InnerList
public object GetSomething() {
return this.InnerList.GetSomething();
}
public void CopyTo(System.Array array, int index) {
this.InnerList.CopyTo(array, index);
}
public System.Collections.IEnumerator GetEnumerator() {
return this.InnerList.GetEnumerator();
}
public int Add(object value) {
return this.InnerList.Add(value);
}
public void Clear() {
this.InnerList.Clear();
}
public bool Contains(object value) {
return this.InnerList.Contains(value);
}
public int IndexOf(object value) {
return this.InnerList.IndexOf(value);
}
public void Insert(int index, object value) {
this.InnerList.Insert(index, value);
}
public void Remove(object value) {
this.InnerList.Remove(value);
}
public void RemoveAt(int index) {
this.InnerList.RemoveAt(index);
}
public object[] ToArray() {
return ((System.Collections.ArrayList)InnerList).ToArray();
}
public object[] ToArray(System.Type type) {
return (object[])(((System.Collections.ArrayList)InnerList).ToArray(type));
}
#endregion
}
[VB]
'This class plays the role of a delegate
Friend Class MyCustomCollectionSlave
Inherits System.Collections.ArrayList
#Region "Methods"
Public Function GetSomething() As Object
'Write some code here
End Function
#End Region
End Class
Public Class MyCustomCollection
Inherits MarshalByRefObject
#Region "Fields"
Private _InnerList As MyCustomCollectionSlave
#End Region
#Region "Properties"
'Through this property, all delegation is done.
Private ReadOnly Property InnerList() As MyCustomCollectionSlave
Get
Return Me._InnerList
End Get
End Property
'The properties below help delegating ArrayList's built-in properties.
Public ReadOnly Property Count() As Integer
Get
Return Me.InnerList.Count
End Get
End Property
Public ReadOnly Property IsSynchronized() As Boolean
Get
Return Me.InnerList.IsSynchronized
End Get
End Property
Public ReadOnly Property SyncRoot() As Object
Get
Return Me.InnerList.SyncRoot
End Get
End Property
Public ReadOnly Property IsFixedSize() As Boolean
Get
Return Me.InnerList.IsFixedSize
End Get
End Property
Public ReadOnly Property IsReadOnly() As Boolean
Get
Return Me.InnerList.IsReadOnly
End Get
End Property
Default Public Property Item(ByVal index As Integer) As Object
Get
Return Me.InnerList.Item(index)
End Get
Set(ByVal value As Object)
Me.InnerList.Item(index) = value
End Set
End Property
#End Region
#Region "Constructors"
Public Sub New()
Me._InnerList = New MyCustomCollectionBase
End Sub
#End Region
#Region "Methods"
//This method simply forwards calls to the GetSomething() method in InnerList
Public Function GetSomething() As Object
Return Me.InnerList.GetSomething()
End Function
'The methods below help delegating ArrayList's built-in methods.
Public Sub CopyTo(ByVal array As System.Array, ByVal index As Integer)
Me.InnerList.CopyTo(array, index)
End Sub
Public Function GetEnumerator() As System.Collections.IEnumerator
Return Me.InnerList.GetEnumerator
End Function
Public Function Add(ByVal value As Object) As Integer
Return Me.InnerList.Add(value)
End Function
Public Sub Clear()
Me.InnerList.Clear()
End Sub
Public Function Contains(ByVal value As Object) As Boolean
Return Me.InnerList.Contains(value)
End Function
Public Function IndexOf(ByVal value As Object) As Integer
Return Me.InnerList.IndexOf(value)
End Function
Public Sub Insert(ByVal index As Integer, ByVal value As Object)
Me.InnerList.Insert(index, value)
End Sub
Public Sub Remove(ByVal value As Object)
Me.InnerList.Remove(value)
End Sub
Public Sub RemoveAt(ByVal index As Integer)
Me.InnerList.RemoveAt(index)
End Sub
Public Function ToArray() As Object()
Return CType(Me.InnerList, ArrayList).ToArray()
End Function
Public Function ToArray(ByVal type As System.Type) As Object()
Return CType(Me.InnerList, ArrayList).ToArray(type)
End Function
#End Region
End Class
The example above is a simple one. A good practice would be
to create a generic base class the same way we created MyCustomCollection, call
it for example MyCustomCollectionBase(Of T). You can use delegation to simulate
multiple inheritance within this class.
Note that we can delegate the behaviors of more than one class;
this allows simulating inheritance not only from a couple of classes as in our
example above, but also from any number of classes.
Then we can derive new classes from
MyCustomCollectionBase(Of T). This has the same effect as deriving them from
the classes inherited and delegated by MyCustomCollectionBase. For example, we
can create a class called MyOrderCollection that is derived from
MyCustomCollectionBase (Of OrderInfo).