views:

496

answers:

3

So in a previous question I asked about implementing a generic interface with a public class and bingo, it works. However, one of the types I'm looking to pass in is one of the built in nullable types such as: int, Guid, String, etc.

Here's my Interface:

public interface IOurTemplate<T, U>
    where T : class
    where U : class
{
    IEnumerable<T> List();
    T Get(U id);
}

So when I implement this like so:

public class TestInterface : IOurTemplate<MyCustomClass, Int32>
{
    public IEnumerable<MyCustomClass> List()
    {
        throw new NotImplementedException();
    }

    public MyCustomClass Get(Int32 testID)
    {
        throw new NotImplementedException();
    }
}

I receive the error message: The type 'int' must be a reference type in order to use it as parameter 'U' in the generic type or method 'TestApp.IOurTemplate'

I've tried to infer the type Int32?, but same error. Any ideas?

+5  A: 

Nullable types don't satisfy class or struct constraints:

C# Language Specification v3.0 (Section §10.1.5: Type parameter constraints):

The reference type constraint specifies that a type argument used for the type parameter must be a reference type. All class types, interface types, delegate types, array types, and type parameters known to be a reference type (as defined below) satisfy this constraint. The value type constraint specifies that a type argument used for the type parameter must be a non-nullable value type.

All non-nullable struct types, enum types, and type parameters having the value type constraint satisfy this constraint. Note that although classified as a value type, a nullable type (§4.1.10) does not satisfy the value type constraint. A type parameter having the value type constraint cannot also have the constructor-constraint.

Mehrdad Afshari
So what's your recommendation?
Jason N. Gaylord
If you don't need constraints, remove them. If you want to use nullable types only, add a value type constraint (`where T:struct`) and use `T?` in the class definition.
Mehrdad Afshari
+2  A: 
ChaosPandion
(embarrased) - thx for pointing out my oversight. :)
Jason N. Gaylord
This is not true. That's why you can't have `Nullable<Nullable<int>>`. See my answer.
Mehrdad Afshari
Well this is what you get for not testing.
ChaosPandion
By you I meant me. Kind of embarrassed here.
ChaosPandion
Don't be. Actually at first, I didn't read the question completely. I just saw `Int32` being used as a nullable type and freaked out and wrote an answer w/o reading completely. Had to delete and post the correct one.
Mehrdad Afshari
If you want to just accept nullable types, you can easily do it by constraining `T : struct` and using `T?` everywhere in the class.
Mehrdad Afshari
Ah yes good point.
ChaosPandion
A: 

Any reason why you need to restrict type U to class?

public interface IOurTemplate<T, U>
    where T : class
{
    IEnumerable<T> List();
    T Get(U id);
}

public class TestInterface : IOurTemplate<MyCustomClass, Int32?>
{
    public IEnumerable<MyCustomClass> List()
    {
        throw new NotImplementedException();
    }

    public MyCustomClass Get(Int32? testID)
    {
        throw new NotImplementedException();
    }
}

FYI: int? is the C# shorthand for Nullable

Fnop