4

I want to create an extendable nested structure and it seems like I should be able to do this using generics, though I may not be using them "properly".

I want to be able to create child classes from GroupType and/or OptionType. The problem is that I can't perform the new operation on the generic types even though I specified they could only be of a certain base type.

Is there any way to do what I'm trying to do?

public class AllInfo<GroupType, OptionType> 
    where GroupType: GroupBase<OptionType>
    where OptionType: OptionBase
{
    public List<string> Names { set; get; }
    public List<GroupType> Groups { set; get; }

    public AllInfo()
    {
        DataSet ds = DatabaseRetreival();
        this.Groups.add(new GroupType(ds["Name"], ds["Type"]));
    }

}

public class GroupBase<OptionType> 
    where OptionType: OptionBase
{
    public string Name { set; get; }
    public string Type { set; get; }
    public List<OptionType> Options { set; get; }

    public GroupBase(string name, string type)
    {
         this.Name = name;
         this.Type = type;

         DataSet ds = DatabaseRetreival(this.Type);
         this.Options.Add(new OptionType(ds["Name"]));
    }
}

public class OptionBase
{
    public string Name { set; get; }

    public OptionBase(string name)
    {
        this.Name = name;
    }
}
Josh Russo
  • 3,080
  • 2
  • 41
  • 62

4 Answers4

4

You have to specify the classes must have a default constructor.

where GroupType: GroupBase<OptionType>, new()

View this article and jump down to the section titled Generic Constraints.

Erik Noren
  • 4,279
  • 1
  • 23
  • 29
  • That doesn't help, as he doesn't use the parameterless constructor. – Guffa Nov 09 '10 at 17:32
  • 1
    Ah, there is no constraint for multiple-parameter constructors though there is an article I ran across using lambdas to which might be used. http://www.ademiller.com/blogs/tech/2007/11/an-alternative-to-the-c-generic-new-constraint/ – Erik Noren Nov 09 '10 at 17:36
  • Serious performance implications of the new() constraint http://blogs.msdn.com/b/zelmalki/archive/2008/12/13/creating-objects-using-generic-new-constraint.aspx @Erik +1 for lambdas. – Squirrelsama May 08 '12 at 17:19
2

You can't specify which constructors a generic class should have. The constructors are not inherited, so even if the base class that you specified has that constructor, a class that derives from it doesn't have to have that constructor.

The only constructor that you can require is the parameterless constructor:

where GroupType: GroupBase<OptionType>, new()

As that only let's you use the parameterless constructor, you would also use a virtual method for putting the data in the object, for example:

GroupType group = new GroupType();
group.Init(ds["Name"], ds["Type"]);
this.Groups.add(group);
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
1

The compiler cannot allow that, because it cannot guarantee that the OptionType has a constructor with the right signature. But you can pass a factory function instead of invoking the constructor directly:

public class Foo<T> 
{
    private List<T> myObjects;

    public Foo(Func<string, T> factory))
    {
        myObjects = new List<T>();
        foreach (string s in GetDataStrings())
            myObjects.Add(factory(s));
    }
}

So if you have a Bar class with a constructor taking a string, you do this:

Func<string,Bar> barFactory = x => new Bar(x);
var foo = new Foo<Bar>(barFactory);
Wim Coenen
  • 66,094
  • 13
  • 157
  • 251
0

The problem you have is foundationally based in very high amounts of class coupling that you are trying to mitigate with inheritance/generics. I suggest you re-examine why you feel this is necessary. This quest will eventually lead you to interfaces, service-based programming, and IoCs like Ninject or Castle Windsor.

However, if you want a quick fix that further increases code complexity (because you don't have non-complex options here aside from changing your coding philosophy), use an abstract/virtual method, maybe call it Bind(), instead of constructors.

[bolded for tl;dr]

Squirrelsama
  • 5,480
  • 4
  • 28
  • 38