Jordi
Jordi

Reputation: 23277

C# List of undefined generic classes?

I've a class like:

class GClass<T1, T2> {}

implementations:

class CClass1<String, String> {}
class CCLass2<String, Double> {}

On my C# code I'd need to define a object like this List<GClass<T1,?>.

Is it possible?

By other hand, I've tested with List<GClass<String, Object>>, however I can't add a object like this:

List<GClass<String, Object>> list = new List<GClass<String, Object>>();
CClass1 c1 = new CClass1();
list.Add(c1);

Compiler dumps me an compilation error.

EDIT

I've tested with it:

public interface IViz<T, TQuery, out TOut>
{
    Configuration.IVizConfiguration<T> VizConfiguration { get; }
    IList<TOut> SelectedValues { get; }

    IEnumerable<TQuery> generate(IEnumerable<T> search);
    Expression<Func<T, bool>> generateExpression(Object selectedVizValue);
    IEnumerable<Expression<Func<T, bool>>> generateExpressions(IEnumerable<Object> selectedVizValues);
}

However, compiler tells me:

Error 3 Invalid variance: The type parameter 'TOut' must be invariantly valid on 'UI.Forms.SearchTool.Visualization.IViz.SelectedValues'. 'TOut' is covariant. D:\projects\living\clients\NetClient\UI\Forms\SearchTool\Visualization\IViz.cs 8 42 UI

Upvotes: 0

Views: 2228

Answers (2)

Simon Karlsson
Simon Karlsson

Reputation: 4129

You can accomplish this behaviour by adding an interface and use the generic modifier out on your type parameter, making it covariant.

From documentation, out (Generic Modifier) :

For generic type parameters, the out keyword specifies that the type parameter is covariant. You can use the out keyword in generic interfaces and delegates.

Covariance enables you to use a more derived type than that specified by the generic parameter. This allows for implicit conversion of classes that implement variant interfaces and implicit conversion of delegate types. Covariance and contravariance are supported for reference types, but they are not supported for value types.

Example:

public interface GInterface<T1, out T2> {}
public class GClass<T1, T2> : GInterface<T1, T2> {}

Usage:

List<GInterface<String, Object>> list = new List<GInterface<String, Object>>();
GClass<string, string> c1 = new GClass<string, string>();
list.Add(c1);

Upvotes: 5

Lasse V. Karlsen
Lasse V. Karlsen

Reputation: 391724

No, you cannot do that but you can define a common interface having only one of the generic types:

interface IClass<T> { }
class GClass<T1, T2> : IClass<T1> { }

class CClass1 : GClass<string, object> { }
class CClass2 : GClass<string, double> { }

Then you can create a list of the common interface:

List<IClass<String>> list = new List<IClass<String>>();
list.Add(new CClass1());
list.Add(new CClass2());

Upvotes: 4

Related Questions