Mechanik
Mechanik

Reputation: 679

C# Generics - Classes implementing other generic classes

I have a

public class A<T> where T : IBase
{
    //Does something
}

I need a second class that behaves like a collection of class A

public class B<A<T>> : IEnumerable<A<T>> where T : IBase
{
}

The problem is that I do not want to create classes like

public class B<A<MyCustomObjectP>> : IEnumerable<A<MyCustomObjectP>>
{
}

public class C<A<MyCustomObjectQ>> : IEnumerable<A<MyCustomObjectQ>>
{
}

and so on.. I would like to let the CustomObject be a generic type parameter that implements IBase.

I found that even doing this is illegal:

public class B<T, U> : IEnumerable<T> where T : A<U> where U : IBase
{
}

How could I achieve this type of behaviour, if this is illegal? Is there a better design pattern of sorts that might help?

Upvotes: 1

Views: 93

Answers (2)

Matt
Matt

Reputation: 26999

You wrote that you need a second class that behaves like a collection of class A.

Since you have other classes (like B) inheriting from IBase as well, which you want to add, you can make the collection a collection of IBase.

Hence the solution would look like this (note that I have used List but you can easily replace that by IEnumerable - but then you have to implement methods like .Add yourself):

void Main()
{
    var items = new CollectionOf<IBase>(); // create list of IBase elements
    items.Add(new A() { myProperty = "Hello" }); // create object of A and add it to list
    items.Add(new B() { myProperty = "World" }); // create object of B and add it to list
    foreach(var item in items)
    {
        Console.WriteLine(item.myProperty);
    }
}

// this is the collection class you asked for
public class CollectionOf<U>: List<U>
where U: IBase
{
    // collection class enumerating A
    // note you could have used IEnumerable instead of List
}

public class A: IBase
{
    // class A that implements IBase
    public string myProperty { get; set; }
}

public class B: IBase
{
    // class B that implements IBase too
    public string myProperty { get; set; }
}

public interface IBase {
    // some inteface
    string myProperty { get; set; }
}

Upvotes: 0

Honza Brestan
Honza Brestan

Reputation: 10947

The IBase constraint is defined on A<T>, so it must be defined again on all generic classes, that want to use A<U> (using U to distinguish from T in A<T> class definition, but it can be called anything). You should be able to do simply:

public class B<T> : IEnumerable<A<T>> where T : IBase { ... }

Upvotes: 1

Related Questions