jbarba
jbarba

Reputation: 91

C# Generics and Generic Constraints

I'm writing a generic abstract class A with type parameter T that I intend to derive with class B.

A has a data member, mX, an instance of class C, with a generic function. This generic function, GetAllOfType(), has one type parameter, T. This type parameter is constrained to a third class, D. GetAllOfType() searches through a container of instances of D, which includes instances of D's derived classes, and returns the subset that are of the type T (hence the constraint to D).

Class D itself does not have a particular data member, int mY, but some derived classes of D do, such as E and F.

public class D
{
}

public class E : D
{
    public int mY;
}

public class F : D
{
    public int mY;
}

public class C
{
    public T[] GetAllOfType<T>() where T : D
    { ... }
}

public class A<T>
{
    private C mX;
    ...
}

public class B : A<E>
{
    ...
}

So here's where my problem starts:

The parameter type that class B uses to inherit and implement class A is a derived class of D. I am attempting to write a function Foo in class A that enumerates through GetAllOfType() and accesses member mY of type E, F, or any other member that has a mY.

public class A<T>
{
    private C mX;

    protected Foo()
    {
        foreach (var c in mX.GetAllOfType<T>())
        {
            c.mY = 0;
        }
    }
}

public class B : A<E>
{
    public Bar()
    {
        Foo();
    }
}

The problem, though, is that GetAllOfType() is constrained, and I am getting an error for not constraining class A as well.

I've tried constraining A as such:

public class A<T> where T : D

But I'm getting a compile time error along the lines of:

Type T' does not contain a definition formY' and no extension method mY' of typeT' could be found (are you missing a using directive or an assembly reference?)

I have also tried to constrain to multiple derived classes:

public class A<T> where T : E, F

But I'm getting an error as well along the lines of:

The class type constraint 'F' must be listed before any other constraints. Consider moving type constraint to the beginning of the constraint list

I've tried switching them:

public class A<T> where T : F, E

Likewise, the result is the same error, but with F switched for E.

Is what I am attempting possible? What am I doing wrong?

Again, I can not change anything about classes C, D, E, and F.

Upvotes: 3

Views: 2047

Answers (1)

Bort
Bort

Reputation: 7618

When adding the constraint on the generic parameter of A,

public class A<T> where T : D

the reason you get the second error, Type T' does not contain a definition for mY' and no extension method mY' of typeT' could be found (are you missing a using directive or an assembly reference?) is, unsurprisingly, because D doesn't have a mY, only the derived classes E and F. The reason

public class A<T> where T : E, F

doesn't work is because you can only specify one base class type constraint (C# doesn't have multiple inheritance). Any further constraints would have to be interfaces, or things like class or new()

If you really can't change anything about these classes then what you're trying to accomplish might be unreasonably difficult, as far as I can tell. I can think of some ugly ways (Reflection, or lots of casting) but that can't be the right path. Maybe there's something clever I'm missing. It would be great if you could introduce an interface (or an intermediate class) with the mY property, and have E and F inherit from that. Then you could constrain T to that instead of D and everything would be honkey dory. Otherwise I don't see any way to know what kind of D you're dealing with, except at runtime.

Upvotes: 2

Related Questions