Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why cannot convert null to type parameter T in c#?

I'm converting a bunch of code from VB to C# and I'm running in to an issue with a method. This VB method works great:

Public Function FindItem(ByVal p_propertyName As String, ByVal p_value As Object) As T

    Dim index As Int32

    index = FindIndex(p_propertyName, p_value)

    If index >= 0 Then
        Return Me(index)
    End If

    Return Nothing

End Function

It allow the return of Nothing(null) for T.

The C# equivalent does not work:

public T FindItem(string p_propertyName, object p_value)
{
  Int32 index = FindIndex(p_propertyName, p_value);

  if (index >= 0) {
    return this[index];
  }
  return null;
}

It won't compile with this error:

The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Nullable<T>'

I need to be able to have the same functionality or it will break a lot of code. What am I missing?

like image 859
Robert Beaubien Avatar asked Jan 25 '15 04:01

Robert Beaubien


2 Answers

Since T can be either reference type or value type, so returning null will not satisfy if T is value type. You should return:

return default(T);

From the link default keyword:

Given a variable t of a parameterized type T, the statement t = null is only valid if T is a reference type and t = 0 will only work for numeric value types but not for structs. The solution is to use the default keyword, which will return null for reference types and zero for numeric value types. For structs, it will return each member of the struct initialized to zero or null depending on whether they are value or reference types. For nullable value types, default returns a System.Nullable, which is initialized like any struct.

Update (2021-09-27)

With the new syntax from C# 7.1, you can be able to return:

return default;
like image 130
cuongle Avatar answered Oct 20 '22 19:10

cuongle


In case of C# you have to use default(T) and it will return 0 not Nothing or Null if you just return T and not T?.

Now In case of VB.net as per your example you say that you return Nothing which is correct but did you try to check return value of that function.

Like

Dim c = <<your class object>>.FindItem("test",Nothing);  // you have to pass valid values.

If you check value of C then it is 0 and not nothing.

Now comes to what happen at MSIL level.

When you compile you VB.net code and check its MSIL. you will find initobj !T and this is instruction for default(T). It is doing this automatically. So if you call your VB.net library from C# then also it will work.

like image 39
dotnetstep Avatar answered Oct 20 '22 19:10

dotnetstep