Jan 18 2007

Interfaces and generic collections in C#

Posted by admin under .NET 2.0

When developing ASPCodeHeaderManager I created a servercontrol for managing javascripts etc in an ASP.NET page.

Later I needed a specific servercontrol to be able to interact with the ASPCodeHeaderManager control. However - I wanted to keep the two controls totally unknown of each other - so  the solution was to create an Interface. By putting the interface into it's own dll I could create by second server by just referencing the interfaces - and not the actual aspcodeheadermanager control. The good stuff in this is of course that it's possible for me to do upgrades to ASPCodeHeaderManager - and my existing code will keep on working as long as I don't chanhe the interface.

This article on dynamically loading dll in net describes to good things about using interfaces - but lets look at the actual interface and implementation I created for aspcodeheadermanager. The smaller classes was simple enough to create an interface for:



    public interface IIncludeScript
    {
        string Path
        {
            get;
            set;
        }
        string StaticPathLevel1
        {
            get;
            set;
        }
        string StaticPathLevel2
        {
            get;
            set;
        }
        int HighestCompressionLevel
        {
            get;
            set;
        }
    }
...


As you can see it's possible to use properties in the interface.

The hard part - which I want to talk to you about is collections:

Basically I wanted the interface to look like this:



    public interface IHeaderManagerInterface
    {
        IList<IIncludeScript> IncludeScripts
        {
            get;
        }
        IList<IMetaData> MetaData
        {
            get;
        }
...



And yes - the interface is ok - however my implementation of it (inside aspcodeheadermanager which implements the IHeaderManagerInterface) got a little harder:




        private List<Stylesheet> m_Stylesheets = new List<Stylesheet>();
        [
        Category("Data"),
        NotifyParentProperty(true),
        PersistenceMode(PersistenceMode.InnerProperty),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content)
        ]
        public List<Stylesheet> IncludeStylesheets
        {
            get
            {
                return m_Stylesheets;
            }
        }


        IList<ASPCodeHeaderManagerInterface.IStylesheet> ASPCodeHeaderManagerInterface.IHeaderManagerInterface.IncludeStylesheets
        {
            get
            {
                return IncludeStylesheets as IList<ASPCodeHeaderManagerInterface.IStylesheet>;
            }
        }




That was what I was hoping to be able to do. However the IncludeStyleSheet is implemented as a List<Stylesheet> and the interface expects IList<IStylesheet> - although the Stylesheet do implement the IStylesheet interface I always got null as result.

So, my (not so happy with) solution so far:



        IList<ASPCodeHeaderManagerInterface.IStylesheet> ASPCodeHeaderManagerInterface.IHeaderManagerInterface.IncludeStylesheets
        {
            get
            {
                System.Collections.Generic.List<ASPCodeHeaderManagerInterface.IStylesheet> oList = new List<ASPCodeHeaderManagerInterface.IStylesheet>();
                foreach (Stylesheet oScript in IncludeStylesheets)
                    oList.Add(oScript as ASPCodeHeaderManagerInterface.IStylesheet);
                return oList;
            }
        }


I simply create a new list - List<IStylesheet> and fill it with the Iinterfaces of the Stylesheet objects so to speak.

Does anybody know of a better solution?

The whole solution is available in the ASPCodeHeadermanager project.