Wildcards in C# generic constraints
Asked Answered
B

3

10

I'm aware that C# doesn't have generic wildcards, and that a similar effect can be achieved by generic methods, but I need to use a wildcard in a field and can't work out if there is any way to encode it.

List<State<Thing>> list;

void AddToList<T>() where T : Thing {
    list.Add(new State<T>());
}

Of course, this doesn't work because the object being added isn't of type State<Thing>, it's of type State<T> where T : Thing. Is it possible to adjust the most internal type of the list to be the Java equivalent of ? extends Thing rather than just Thing?

Barnwell answered 8/12, 2011 at 7:0 Comment(3)
Can you declare your list as List<State<T>> where T : Thing?Santana
@abatishchev: maybe post it as an answer?Orthoscope
@konrad: DoneSantana
I
4

Note that C# 4 does have additional variance support, but it does not apply in the List<T> case, for various reasons (has both "in" and "out" methods, and is a class).

I think, however, the way to address this is with something like:

interface IState { // non-generic
    object Value { get; } // or whatever `State<Thing>` needs
}
class State<T> : IState {
    public T Value { get { ...} } // or whatever
    object IState.Value { get { return Value; } }
}

and

List<IState> list; ...

which will then allow you to add any State<T>. It doesn't really use much of the T, and a cast would be needed to get from the object to T, but .... it will at least work.

Iridescent answered 8/12, 2011 at 7:8 Comment(2)
I really don't understand why can't I cast as the following: (State<Thing>)new State<T> while T : Thing! But can (Thing)new T()Santana
@Santana because a SomeSpecificThing is a Thing; but it is not true that a State<SomeSpecificThing> is a State<Thing>. There is no inheritance etc. If it were a generic interface, if could potentially be IState<out Thing>, in which case the 4.0 variance rules start to apply, and then yes, there is a cast from IState<SomeSpecificThing> to IState<Thing>.Iridescent
U
3

You could try something like this :

    interface IState<out T> { }
    class State<T> : IState<T> { }
    class Thing {}

    List<IState<Thing>> list;

    void AddToList<T>() where T : Thing
    {
        list.Add(new State<T>());
    }
Uniat answered 8/12, 2011 at 8:32 Comment(1)
I would prefer this, but I can't use C# 4.Barnwell
S
0

Declare your list as the following:

class State<T> where T : Thing
{
    ...

    List<State<T>> list = new List<State<T>>();
    // or
    public class StateList<T> : List<State<T>>
    {
         void AddToList(T item);
    }
}

then compiler will be able to convert.

Santana answered 8/12, 2011 at 9:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.