Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I constraint a generic type parameter to only accept nullable value types in C#?

The where T : struct constraint lets one to limit the domain of acceptable type parameters to the set of value types (as compared to the superset of types including both value and reference types) only but also seems to forbid nullable types altogether although nullable doesn't necessarily mean a reference type in modern versions of C#.

What if I'd like to accept value types with added nullability like int?, DateTime? etc while rejecting natively-nullable reference types like string, IList etc? Is it possible to define the constraints this way? How if it is?

I am actually curious to learn to implement both the scenarios: when the type used as the parameter must be both value and nullable and when a nullable value type is to be accepted though as well as a non-nullable value type and I consider these related closely enough to excuse mentioning both so I'd appreciate a humble commentary about the second case and choose an answer including it as a better one (given another one is not going to be really better in other ways) if more than one answer will be submitted and I'll have to choose, but what I actually need right now is the first case (to always require a type that is both nullable and is a value type at the same time) and I also believe the second case is going to be pretty straightforward given the knowledge of the first, not to mention it is not a good manner to insist on gluing 2 questions into one so I will absolutely appreciate and accept an answer dealing with the first case only too.

like image 983
Ivan Avatar asked Dec 19 '22 08:12

Ivan


2 Answers

It's not exactly what you want, but maybe you could use a type constraint of IConvertible? As an interface, it is nullable, and is implemented by Boolean, SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Decimal, DateTime, Char, and String.

class MyClass<T> where T : IConvertible
{
    //Etc
}
like image 111
John Wu Avatar answered Dec 20 '22 21:12

John Wu


You can't. Nullable<T> are not valid constraint for generics in C#.

When you try something like class X<T,U> where T : Nullable<U> you get following error:

'U?' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.

If you need to accept both T and Nullable<T> as method parameters you can just provide overrides:

class X<T>  where T : struct
{
   public void R(T arg){ Console.WriteLine("Non nullable: {0}", arg);}
   public void R(Nullable<T> arg){Console.WriteLine("Nullable: {0}", arg);}
}

And then you can call either version:

X<int> r = new X<int>();
r.R((int?)4);
r.R(4);

In your type deals with just Nullable values you can simply constraint to T:struct but everywhere inside your class use Nullable<T> for parameters and fields.

More discussions on particular aspects - C# generic type constraint for everything nullable and related questions.

like image 33
Alexei Levenkov Avatar answered Dec 20 '22 21:12

Alexei Levenkov