views:

99

answers:

2

Hi

I have two objects MetaItems and Items.

MetaItem is template for objects and Items contains actual values. For example "Department" is treated as meta-item and "Sales", "UK Region", "Asia Region" are treated as items.

Additionally I want to maintain parent-child relation on these meta-items and items.

I have following code for same -

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WpfApplication12
{
    public interface IEntity
    {
        int Id { get; set; }

        string Name { get; set; }
    }

    public interface IHierachy<T>  
    {
        IHierachy<T> Parent { get; }

        List<IHierachy<T>> ChildItems { get; }

        List<IHierachy<T>> LinkedItems { get; }

    }

    public class Entity : IHierachy<IEntity>, IEntity
    {

        #region IObject Members

        private int _id;
        public int Id
        {
            get
            {
                return _id;
            }
            set
            {
                _id = value;
            }
        }

        private string _name;

        public string Name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
            }
        }

        #endregion

        #region IHierachy<IEntity> Members

        public IHierachy<IEntity> _parent;
        public IHierachy<IEntity> Parent
        {
            get
            {
                return _parent;
            }
        }

        private List<IHierachy<IEntity>> _childItems;

        public List<IHierachy<IEntity>> ChildItems
        {
            get
            {
                if (_childItems == null)
                {
                    _childItems = new List<IHierachy<IEntity>>();
                }
                return _childItems;
            }
        }

        private List<IHierachy<IEntity>> _linkedItems;

        public List<IHierachy<IEntity>> LinkedItems
        {
            get
            {
                if (_linkedItems == null)
                {
                    _linkedItems = new List<IHierachy<IEntity>>();
                }
                return _linkedItems;
            }
        }
        #endregion
    }


    public class Item : Entity
    {
    }

    public class MetaItem : Entity
    {
    }

}

Following is my test class -

public class Test
{
    public void Test1()
    {
        MetaItem meta1 = new MetaItem() { Id = 1, Name = "MetaItem1"};

        MetaItem meta2 = new MetaItem() { Id = 1, Name = "MetaItem 1.1"};

        Item meta3 = new Item() { Id = 101, Name = "Item 1" };


        **meta1.ChildItems.Add(meta3);** // this line should not compile.
        meta1.ChildItems.Add(meta2)  // This is valid and gets compiled.
    }
}

In the test class, when I am buidling parent-child relation, I can add item as a child object for meta-item object. Here I want compilation error to be generated.

Can someone help me in achiving this.

-Regards Raj

A: 

Why don't you think that line should compile? It looks completely valid.

The ChildItems list is public. If you don't want them to be able to add to the list then you will need to wrap your own collection or use the ReadOnlyCollection<IHierachy<IEntity>>.

Oh, you have fixed your question. I think the solution is to make the Entity class generic.

using System.Collections.Generic;

namespace WpfApplication12
{
    public interface IEntity
    {
        int Id { get; set; }
        string Name { get; set; }
    }

    public interface IHierachy<T>
    {
        IHierachy<T> Parent { get; }
        List<IHierachy<T>> ChildItems { get; }
        List<IHierachy<T>> LinkedItems { get; }
    }

    public class Entity<T> : IHierachy<T>, IEntity
    {
        private int _id;
        public int Id
        {
            get { return _id; }
            set { _id = value; }
        }

        private string _name;
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        public IHierachy<T> _parent;
        public IHierachy<T> Parent
        {
            get
            {
                return _parent;
            }
        }

        private List<IHierachy<T>> _childItems;
        public List<IHierachy<T>> ChildItems
        {
            get
            {
                if( _childItems == null )
                {
                    _childItems = new List<IHierachy<T>>();
                }
                return _childItems;
            }
        }

        private List<IHierachy<T>> _linkedItems;
        public List<IHierachy<T>> LinkedItems
        {
            get
            {
                if( _linkedItems == null )
                {
                    _linkedItems = new List<IHierachy<T>>();
                }
                return _linkedItems;
            }
        }
    }


    public class Item : Entity<Item>
    {
    }

    public class MetaItem : Entity<MetaItem>
    {
    }

    public class Test
    {
        public void Test1()
        {
            MetaItem meta1 = new MetaItem() { Id = 1, Name = "MetaItem1"};
            MetaItem meta2 = new MetaItem() { Id = 1, Name = "MetaItem 1.1"};
            Item meta3 = new Item() { Id = 101, Name = "Item 1" };

            meta1.ChildItems.Add(meta3); // this line should not compile.
            meta1.ChildItems.Add( meta2 );  // This is valid and gets compiled.
        }
    }

}
Jerod Houghtelling
I think he doesn't want to allow adding Item as a child of MetaItem (even though code wise, both are of type Entity). In otherwords, only MetaItem.ChildItems should only contain other MetaItem's. I'm not familiar with the Entity stuff, so my guess would be to change ChildItem to be a list of MetaItems...
Alan
Ah, yes he has fixed the question and you are totally correct. You would need to make the Entities/Hierachies more generic. I am fixing my solution now.
Jerod Houghtelling
+2  A: 

The code is compiling because ChildItems will be IList<Entity>, which includes both Item and MetaItem. If you were to make Entity generic:

public class Entity<T> : IHierachy<T>, IEntity where T : IEntity { ... }

Then you would define Item and MetaItem like this:

public class Item : Entity<Item> { }

public class MetaItem : Entity<MetaItem> { }

In which case their ChildItems would be of the correct, more restricted, type.

dahlbyk
Ok, I got it to work, after changing references to `IEntity` inside `Entity<T>` to `T`. Inheriting a specialization on yourself is an interesting technique.
Steven Sudit
Yeah, completing the `Entity<T>` change was left as an exercise. :) Definitely a useful technique for specific scenarios.
dahlbyk
Hi dahlbyk,Ya. Adding necessary changes with above changes its working perfect.Thanks.
Raj