Reputation: 7963
I have a little problem when it comes to making Generics work in C#:
I have the following class:
public abstract class OphControl<TDataModel> : Control
where TDataModel : OphDataModel, new()
{
/// <summary>
/// The data model for this control.
/// </summary>
public TDataModel DataModel { get; private set; }
public IEnumerable<OphControl<OphDataModel>> OphControls {
get {
return Controls.Cast<Control>().Where(control => control is OphControl<OphDataModel>).Cast<OphControl<OphDataModel>>();
}
}
protected OphControl() {
DataModel = new TDataModel();
}
}
My problem is, that the OphControls
property won't compile, because OphDataModel
is abstract, and therefore I suppose it cannot be sure at compile-time that OphDataModel has a zero-args public constructor (notice the new()
constraint on TDataModel
).
I'm not even sure if this is the right way to go about it. What I really want is something like OphControl<? extends OphDataModel>
from Java. I tried adding out
to my TDataModel
in the class declaration, but it tells me only delegates and interfaces can have covariant type parameters.
So how do I get around this pickle?
Upvotes: 1
Views: 285
Reputation: 5464
Here are a few things of confusion. First, OphControl<TDataModel>
does not derive from OphControl<OphDataModel>
and you are correct about the out
keyword (covariance/contravariance), they can only be used with delegates and interfaces. Since it is not a base class, you may not be able to cast it.
Unlike java, c# does not support generic wildcards (...<? extends ...>
). The work around is to create a non-generic version and make it the base class.
public abstract class OphControl : Control { ... }
public abstract class OphControl<TDataModel> : OphControl
where TDataModel : OphDataModel, new() { ... }
Unfortunately, the base class cannot have the DataModel property because c# does not support covariant return types either.
At least you can have
public IEnumerable<OphControl> OphControls {
get {
return Controls.OfType<OphControl>();
}
}
Upvotes: 1
Reputation: 152566
I thing you just need to change the generic parameter on OphControls
:
public IEnumerable<OphControl<TDataModel>> OphControls {
get {
return Controls.Cast<Control>().Where(control => control is OphControl<TDataModel>).Cast<OphControl<TDataModel>>();
}
}
This should compile, but without knowing more about your classes it's hard to say if this is right
Upvotes: 0