Share via


SYSK 264: Restricting Item Types in Generic Collections

Say, you have implemented the following data class called Message in a YourCompany.DataContracts.Shared assembly (code below).

When creating a collection of messages class, some may choose to implement it similar to the code below:

[DataContract(Namespace = ""), Serializable]

public class MessageCollection : System.Collections.Generic.SortedDictionary<DateTime, Message>

{

}

 

The problem with this approach is that if you created a class that derives from the Message class, let’s call it MessageEx, and you want a collection of the MessageEx classes, you’ll either have to create a new collection class (e.g. MessageExCollection), or you’ll end up writing a lot of code casting the collection items to the MessageEx type.

 

A better, in my opinion, choice is to create a generic collection, and restrict the type of items that are allowed to be inserted into such collection. Here is what I mean:

 

#region MessageCollection

    [DataContract(Namespace = ""), Serializable]

    public class MessageCollection<T> : System.Collections.Generic.SortedDictionary<DateTime, T> where T : Message

    {

        public void Add(T item)

        {

            base.Add(item.CreatedOn, item);

        }

        public T this[long recordID]

        {

            get

            {

                T result = default(T);

                foreach (T item in base.Values)

                {

                    if (item.RecordID == recordID)

                    {

                        result = item;

                        break;

                    }

                }

                return result;

            }

        }

// TODO: add other methods/properties

// (e.g. get by instance id, get by index, etc)

    }

#endregion

Now, you can have a Message class and MessageEx class, and instanced of both classes can be inserted into MessageCollection. And yes, no casting required when inserting or retrieving and using the message item!

 

[DataContract(Namespace = ""), Serializable]

public class MessageEx : YourCompany.DataContracts.Shared.Message

{

    private string _someOtherData;

    [DataMember]

    public string SomeOtherData

    {

    get { return _someOtherData; }

        set { _someOtherData = value; }

    }

}

namespace YourCompany.DataContracts.Shared

{

    #region Message

    [DataContract(Namespace = ""), Serializable]

    public class Message

    {

        private string _instanceID = Guid.NewGuid().ToString();

        private long _recordID;

        private string _text;

        private DateTime _createdOn;

        private string _createdBy;

        public Message()

        {

        }

        public Message(long recordId, string text, DateTime createdOn, string createdBy)

        {

            _recordID = recordId;

            _text = text;

            _createdOn = createdOn;

            _createdBy = createdBy;

        }

        [DataMember]

        public string InstanceID

        {

            get { return _instanceID; }

            set { _instanceID = value; }

        }

        [DataMember]

        public long RecordID

        {

            get { return _recordID; }

            set { _recordID = value; }

        }

        [DataMember]

        public string Text

        {

            get { return _text; }

  set { _text = value; }

        }

        [DataMember]

        public DateTime CreatedOn

        {

            get { return _createdOn; }

            set { _createdOn = value; }

        }

        [DataMember]

        public string CreatedBy

   {

            get { return _createdBy; }

            set { _createdBy = value; }

        }

    }

    #endregion

    [DataContract(Namespace = ""), Serializable]

    public class MessageEx : YourCompany.DataContracts.Shared.Message

    {

        private string _someOtherData;

        [DataMember]

        public string SomeOtherData

        {

            get { return _someOtherData; }

            set { _someOtherData = value; }

        }

    }

 

Usage:

 

MessageCollection<MessageEx> messages =

new MessageCollection<MessageEx>();

. . .

// No casting required :)

MessageEx message = messages[recordID];