ProfK
ProfK

Reputation: 51063

How can I internally keep an always nullable equivalent of a generic type parameter?

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

Answers (5)

Jeppe Stig Nielsen
Jeppe Stig Nielsen

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

Arne
Arne

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

Carra
Carra

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

Jord&#227;o
Jord&#227;o

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

usr
usr

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

Related Questions