Duncan Lukkenaer
Duncan Lukkenaer

Reputation: 13994

How to make Generic parameter T Nullable in C#?

I'm creating a generic method which should be able to return null.

As an example I've created this method GetSecondSmallest(List<T>) below. This function loops through all of the IComparable items and returns the second smallest item if possible. If this item does not exist it returns null.

public T? GetSecondSmallest<T>(List<T> items) where T : Nullable, IComparable
{
    if (items.Count == 0) return null;

    T smallest = items[0];
    T? secondSmallest = null;

    // Find second smallest by looping through list

    return secondSmallest;
}

Two example usages of this method would be:

GetSecondSmallest(new List<int> {4, 2, 3, 1, 6, 8}) // Should return 2
GetSecondSmallest(new List<MyComparable> {new MyComparable('x')}) // Should return null

When you try to compile this code you'll see what the problem is here:

Error CS0717 'Nullable': static classes cannot be used as constraints

How can I make this method return either an instance of T or null?


EDIT: I have already seen this question, but this does not answer my question, because in my situation the parameter is also generic, and should be Nullable. So the provided answers there aren't applicable.

Upvotes: 4

Views: 7623

Answers (3)

Grax32
Grax32

Reputation: 4069

Use a wrapper class such as Tuple to wrap the resulting value. In the example below, null is returned if there is no second smallest item, otherwise a Tuple is returned with the second smallest value.

public static void Main()
{
    var result1 = GetSecondSmallest(new List<int>
    {
    4, 2, 3, 1, 6, 8
    }); // Should return 2

    var result2 = GetSecondSmallest(new List<MyComparable>
    {
    new MyComparable('x')
    }); // Should return null

    Console.WriteLine("result1=" + result1.Item1);
    Console.WriteLine("result2 == null: " + (result2 == null));
}

public static Tuple<T> GetSecondSmallest<T>(List<T> items)where T : IComparable
{
    return items.Skip(1).Select(v => Tuple.Create(v)).FirstOrDefault();
}

Upvotes: 1

Taras Kovalenko
Taras Kovalenko

Reputation: 2393

Change the return type to Nullable, and call the method with the non nullable parameter

Simple example:

static void Main(string[] args)
{
    int? i = GetValueOrNull<int>(null, string.Empty);
}


public static Nullable<T> GetValueOrNull<T>(DbDataRecord reader, string columnName) where T : struct
{
    object columnValue = reader[columnName];

    if (!(columnValue is DBNull))
        return (T)columnValue;

    return null;
}

Nullable type as a generic parameter possible?

UPD

Like this:

public Nullable<T> GetSecondSmallest<T>(List<T> items) where T : IComparable
{
    if (items.Count == 0) return null;

    Nullable<T> smallest = items[0];
    Nullable<T> secondSmallest = null;

    // Find second smallest by looping through list

    return secondSmallest;
}

Upvotes: 1

Patrick Hofman
Patrick Hofman

Reputation: 157098

You can't narrow T down as nullable or an object. You have to make two methods, one for T and one for T?.

public T? GetSecondSmallestAsNullable<T>(List<T> items) where T : struct
{
    return null;
}

public T GetSecondSmallestAsClass<T>(List<T> items) where T : class
{
    return null;
}

Upvotes: 4

Related Questions