errcw
errcw

Reputation: 329

Adding generic object to generic list in C#

I have class where the relevant part looks like

class C {
    void Method<T>(SomeClass<T> obj) {
        list.Add(obj);
    }
    List<?> list = new List<?>();
}

How should I define the list so that the class compiles?

I want a list of type List<SomeClass<?>>, that is a list of objects of SomeClass where each object can have any type parameter. The Java ? construct allows this; what is the C# equivalent? If no such thing exists, is there a suitable workaround? (A List<object> would do but is terribly ugly.)

Upvotes: 13

Views: 47310

Answers (5)

Gusdor
Gusdor

Reputation: 14332

Personally, I would do this where possible; move the generic parameter from the method, to the class.

class C<T> {
    void Method(SomeClass<T> obj) {
        list.Add(obj);
    }
    List<?> list = new List<?>();
}

If your generic list is a member, it stands to reason that the class should be constructed with this in mind. It is hard for us to suggest the best pattern without more usage context for the class.

Upvotes: 0

&#208;аn
&#208;аn

Reputation: 10875

I don't know anything about Java's ? construct, but I think the following most closely preserves your existing syntax while also matching your description.

    class SomeClass<T>
    {
    }

    class C
    {
        void Add<T>(SomeClass<T> item)
        {
            Type type = typeof(SomeClass<T>);
            if (!list.ContainsKey(type))
                list[type] = new List<SomeClass<T>>();
            var l = (List<SomeClass<T>>)list[type];
            l.Add(item);
        }

        public void Method<T>(SomeClass<T> obj)
        {
            Add(obj);
        }
        readonly Dictionary<Type, object> list = new Dictionary<Type, object>();
    }

test it with the following:

    class Program
    {
        static void Main(string[] args)
        {
            var c = new C();
            var sc1 = new SomeClass<int>();
            var sc2 = new SomeClass<String>();
            c.Method(sc1);
            c.Method(sc2);
            c.Method(sc1);
            c.Method(sc2);
        }
    }

Upvotes: 2

Mehrdad Afshari
Mehrdad Afshari

Reputation: 422252

Unfortunately, there is no direct equivalent in C# 3.0 as generics are invariant. You'll be able to do something like this in a graceful manner using C# 4.0 safe co/contra-variance feature. To workaround it, you could inherit SomeClass<T> from a nongeneric base and create a List<BaseClass> instead. If each instance of the class should hold only one type, you could make the class itself generic and set the type parameter there.

Upvotes: 2

Reed Copsey
Reed Copsey

Reputation: 564851

To do what you want, you have two options.

You can use List<object>, and handle objects. This will not be typesafe, and will have boxing/unboxing issues for value types, but it will work.

Your other option is to use a generic constraint to limit to a base class or interface, and use a List<Interface>.

Upvotes: 3

Daniel Schaffer
Daniel Schaffer

Reputation: 57872

I don't think you can do this in C#... you would have to add the type parameter to the class:

class C<T> {
    void Method(SomeClass<T> obj) {
        list.Add(obj);
    }
    List<SomeClass<T>> list = new List<SomeClass<T>>();
}

The other option would be to use an interface:

class C {

    void Method<T>(T obj)
         where T : ISomeClass {
        list.Add(obj);
    }
    List<ISomeClass> list = new List<ISomeClass>();
}

Upvotes: 14

Related Questions