5

Consider the following scenario.

Document -> Section -> Body -> Items

Document has sections, a section contains a body. A body has some text and a list of items. The items is what the question is about. Sometimes the items is a basic list of string, but sometimes the items contain a list of a custom datatype.

So:

    public class Document
    {
        public Section[] Sections{get;set;}
    }

    public class Section
    {
         public SectionType Type{get;set;}
         public Body {get;set;}
    }

    public class Body
    {
      //I want the items to be depending on the section type.
      //If e.g. the sectiontype is experience, I want the Items to be created with type //Experience. If sectiontype is default I want the Items to be created with type string
       public Items<T> Items {get;set;}
    }

   public class Items<T>:IEnumerable, IEnumerator
   {
    // Do all the plumbing for creating an enumerable collection
    }

   public class Experience
   {
      public string Prop1{get;set;}
      public string Prop2 {get;set;}
   }

I can´t get this to work. The property Items has to be defined by a type in order to compile. I am stuck here. I can fix this easily by creating a Section class for each of the kind of sections I use. But the thing is that all the other code is the same and all the operations on the section will be the same. The only thing different is the type of list used in the Body.

What is the best practice for this. I have tried generics, abstraction etc. I can make it work if creating the Items class directly from the calling program, but I can´t get it to work if Items is declared a property on another class.

I can provide more details if needed. Thank you guys and girls for your support.

Mounhim
  • 1,674
  • 1
  • 17
  • 32
  • Maybe mentioning anonymous type in the title is useless here... – digEmAll Feb 03 '11 at 17:17
  • If sectionType is a property on the Section class, what impact does changing this have on the Items that are in the Body? Do you need to recreate them? I think you should make the sections class generic. – Kell Feb 03 '11 at 17:17
  • Is there a reason why you're not simply making an Item abstract class then having something like a StringItem and any other custom Item types you need then representing your Items property as simply a List? To me that seems like a natural way to represent the structure you're describing. – HasaniH Feb 03 '11 at 17:19
  • 1
    You say that Items can *be* a list of strings, or can *contain* a list of something else. Are you trying to draw a distinction between *being* a list and *containing* a list here? Can you describe in more detail what Items is intended to represent? I think the problem here is fundamentally that it is not clear what "Items" is; once you crisp up for us what it is supposed to be it will be easier to find a representation that works in the type system. – Eric Lippert Feb 03 '11 at 17:54

4 Answers4

2

This class isn't valid:

public class Body
{
    public Items<T> Items {get;set;}
}

You need to define a concrete type here OR make Body a generic type also. So either:

public class Body<T>
{
    public Items<T> Items {get;set;}
}

or:

public class Body
{
    public Items<MyClass> Items {get;set;}
}
Keltex
  • 26,220
  • 11
  • 79
  • 111
  • Obviously, the second option requires to make generic also `Section` and `Document`, and conseguently every documents would be forced to have the same type of items. It can be reasonable, it depends on what actually the OP needs... – digEmAll Feb 03 '11 at 17:23
1

Make an interface for Items

   public interface IItems: IEnumerable, IEnumerator{
   }

   public class Items<T>: IItems
   {
    // Do all the plumbing for creating an enumerable collection
    }

Then use that everywhere else.

public class Body
{
  //I want the items to be depending on the section type.
  //If e.g. the sectiontype is experience, I want the Items to be created with type //Experience. If sectiontype is default I want the Items to be created with type string
   public IItems Items {get;set;}
}
Mike Ruhlin
  • 3,546
  • 2
  • 21
  • 31
  • This worked like a charm for me. Thank you very much for such a fast response! – Mounhim Feb 03 '11 at 17:52
  • 1
    Basically, is like defining `Items` property as `IEnumerable` or `IEnumerable`, I can't see any clear advantage to use this more convoluted approach... – digEmAll Feb 03 '11 at 17:57
  • Well, for the trivialized example, no. But I'm assuming that in real life he actually has some implementation code that makes an Item different from an IEnumerable... – Mike Ruhlin Feb 03 '11 at 18:49
0

The most obvious option is declare your list of type object, but then you have to deal with the performance hit of boxing and unboxing of the object. I think I would create an interface that defines the behavior you are looking for from the item and make sure each item implements that interface.

public IMyInterface
{
    string dosomething();
}    

public Items<IMyInterface> Items {get;set;}

Then you could ask each item to do something useful as you are iterating through them.

dustyhoppe
  • 1,783
  • 16
  • 20
0

This could work for you:

public class Document<T> where T: IEnumerable, IEnumerator
{
    private Section<T>[] Sections{get;set;}
}

private class Section<T>
{

     private Body<T> body {get;set;}
}

private class Body<T>
{      
   private Items<T> Items {get;set;}
}

private class Items<T>:IEnumerable, IEnumerator
{
    // Do all the plumbing for creating an enumerable collection
    public IEnumerator GetEnumerator()
    {
        return (IEnumerator)this;
    } 
    /* Needed since Implementing IEnumerator*/
    public bool MoveNext()
    {            
        return false;
    } 
    public void Reset()
    {

    } 
    public object Current
    {
        get{ return new object();}
    } 
}
Sorax
  • 2,205
  • 13
  • 14