Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Restricting a generic to things that can be null

I'd like to restrict a generic I'm coding to anything that can be null. That's basically any class + System.Nullable (e.g. int? and such).

For the class part, it's rather easy:

public class MyGeneric<T> where T : class {} 

But then, this doesn't allow me to do this:

var myGeneric = new MyGeneric<int?>(); 

or this:

var myGeneric = new MyGeneric<Nullable<int>>(); 

The compiler complains with:
error CS0452: The type 'int?' must be a reference type in order to use it as parameter 'T' in the generic type or method 'Test.MyGeneric'

So I tried addind System.Nullable as accepted types for T:

public class MyGeneric<T> where T : class, System.Nullable {} 

But it won't do. The compiler returns the following error:
error CS0717: 'System.Nullable': static classes cannot be used as constraints

I then tried

public class MyGeneric<T> where T : class, INullable {} 

It does compile, but then when I do:

var myGeneric = new MyGeneric<string>(); 

The compiler returns this error:
error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Test.MyGeneric'. There is no implicit reference conversion from 'string' to 'System.Data.SqlTypes.INullable'.

So, the question is: Is it even possible to restrict a generic to anything that can be null, and of so, how?

For reference, I'm using VS2010 / C# 4.0

edit
I was asked what I want to do with it. Here's an example:

namespace Test {     public class MyGeneric<T> where T : class     {         private IEnumerable<T> Vals { get; set; }          public MyGeneric(params T[] vals)         {             Vals = (IEnumerable<T>)vals;         }          public void Print()         {             foreach (var v in Vals.Where(v => v != default(T)))             {                 Trace.Write(v.ToString());             }             Trace.WriteLine(string.Empty);         }     }      class Program     {         static void Main(string[] args)         {             MyGeneric<string> foo =                  new MyGeneric<string>("a", "b", "c", null, null, "g");             foo.Print();         }     } } 

This program prints abcg in the debug console.

like image 311
joce Avatar asked Apr 20 '11 23:04

joce


People also ask

What are generic constraints?

The where clause in a generic definition specifies constraints on the types that are used as arguments for type parameters in a generic type, method, delegate, or local function. Constraints can specify interfaces, base classes, or require a generic type to be a reference, value, or unmanaged type.

Can generic classes be constrained?

You can constrain the generic type by interface, thereby allowing only classes that implement that interface or classes that inherit from classes that implement the interface as the type parameter. The code below constrains a class to an interface.

How do I restrict a generic class in C#?

You can specify one or more constraints on the generic type using the where clause after the generic type name. The following example demonstrates a generic class with a constraint to reference types when instantiating the generic class.

How do I return a generic null?

So, to return a null or default value from a generic method we can make use default(). default(T) will return the default object of the type which is provided.


1 Answers

No, there is no way to do this at compile-time.

Personally, I'd just let T be anything, then I'd check its validity in a static constructor:

public class MyGeneric<T> {     static MyGeneric()     {         var def = default(T);          if (def is ValueType && Nullable.GetUnderlyingType(typeof(T)) == null)         {             throw new InvalidOperationException(                 string.Format("Cannot instantiate with non-nullable type: {0}",                     typeof(T)));         }     } } 
like image 162
user541686 Avatar answered Sep 20 '22 17:09

user541686