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.
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.
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.
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.
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.
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))); } } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With