Reputation: 51063
A code example first is essential I think. I'm trying to build a view model that I will use for all properties that need dropdown controls, and this is a start:
public class ListProperty<TListItem, TValue>
{
private readonly string _valuePropertyName = "Id";
private readonly string _textPropertyName = "Name";
public TValue Value { get; set; }
private IEnumerable<TListItem> _list;
public ListProperty(IEnumerable<TListItem> list)
{
_list = list;
}
}
I would like to have an underlying property for Value
that is always nullable, so if TValue
is a reference type, the underlying type will just be TValue
, but when TValue
is a value type, the underlying type must be Nullable<TValue>
.
MORE: The reason I want this, is to know whether the Value
property has been assigned to or not. To do this without my requirement would involve having to type value as Object
, which smells bad to me.
Upvotes: 2
Views: 90
Reputation: 61952
I'm not sure I understand your problem, but as your class stands now, you can use any type for TValue
, including a nullable type:
new ListProperty<string, string>(someList1); // reference type: string
new ListProperty<string, DateTime?>(someList2); // nullable value type: DateTime?
new ListProperty<string, DateTime>(someList3); // non-null value type: DateTime
If you want to prevent the last use only, I think it's impossible with constraints on TValue
in the class declaration. But you could make a check runtime by adding a static constructor like this:
static ListProperty()
{
if (default(TValue) != null)
throw new ArgumentException("Type argument must allow null", "TValue");
}
Upvotes: 0
Reputation: 2146
Simple and short: as you need to instantiate different versions at different places, why not
ListProperty<SomeListItemType, SomeReferenceType>
and
ListProperty<SomeOtherListItemType, SomeValueType?>
where appropriate? But maybe i've got something wrong...
Upvotes: 1
Reputation: 17964
The best I can think of is passing three parameters and just pass one or the other:
public class ListProperty<TListItem, TValueStruct, TValueClass>
where TValueStruct : struct
where TValueClass : class
{
}
Upvotes: 1
Reputation: 56467
You could try splitting them in different classes:
public abstract class ListProperty<TListItem, TValue> {
public TValue Value { get; set; }
...
}
public class RefListProperty<TListItem, TValue> :
ListProperty<TListItem, TValue> where TValue : class {
}
public class ValListProperty<TListItem, TValue> :
ListProperty<TListItem, Nullable<TValue>> where TValue : struct {
}
Upvotes: 1
Reputation: 171178
This is not possible. The C# nullable syntax T?
is (mostly) a shortcut for System.Nullable<T>
. And System.Nullable
does not allow reference types for T
. That's why you cannot apply ?
to a (generic) type that is potentially a reference type. You can restrict TValue
to struct
however.
Or, you can write your own Nullable
helper struct that allows reference types.
Upvotes: 3