开发者

Return null from generic method

How do I return null value from a generic method?

protected T ValueOrDefault<T>(I开发者_如何转开发DataReader reader, int ordinalId)
        {  
  Type t = typeof(reader.GetValue(ordinalId));
    if (t.IsValueType){
        //Struct. How do I return null?
    } else { 
        //Class
        //just return  null
        return  default(T);
    }
}


default(T) works in both cases.


default(T) does function in both cases, but its meaning is slightly different for value types. It literally returns the default value of the type. In the case of Method<int>, it will return 0, not null.

UPDATE: Given your method signature:

protected T ValueOrDefault<T>(IDataReader reader, int ordinalId)

You can't return Nullable<T> in the case of a value type and type T in the case of a reference type. That would have to be two different methods.


Obviously you can only return null if the return type is either Nullable<T> or a reference type. Normal value-types have no null.

For reference types default(T) is null, and for Nullable<T> it's null too. So you can use default(T) in both cases where null exists.

If the type is another value-type default(T) will not be null, but since there is no null that wouldn't make sense anyways.


It is not possible to simply have a method that has return type T if T is a reference-type/Nullable<T> and T? for normal value types.

One could try to define something like this, but it won't compile because the compiler doesn't understand that the generic constraints are mutually exclusive. It just doesn't consider generic constraints for that.

T? a<T>()
  where T:struct
{
}

T a<T>()
  where T:class
{
}

You need to make these methods different in some other way. Either by using different names or different parameters.


If you want to return T? if it's a value type, you have to use two separate methods. However, there is a complexity, in that methods can't differ only by their return type (there's also issues around the generic args not being part of a method signature). So you have to provide a 'stub' method parameter which the compiler uses to resolve which method to call:

public T MyMethod<T>(T stub) where T : class {
    // ...
    return null;
}

public T? MyMethod<T>(T? stub) where T : struct {
    // ...
    return null;
}

// this will then compile...
string s = MyMethod<string>(null);
int? i = MyMethod<int>(null);


It's not legal to return null for an unconstrained T value. Consider for instance if T is instantiated as a value type. In that case null would not be a legal value and hence the code is illegal.

What you're looking for is default(T). This will work for both value and reference types. For reference types it will produce null and for value types it will produce the zero initialized value.


In C# 9, it is possible to have a single method return null for reference and for nullable value types. Note that string and string? are exactly the same type but int and int? are different (Int32 and Nullable).

[TestMethod]
public void TestGenericNull()
{
  static T? GetDefault<T>(bool wantNullable) => wantNullable ? default(T?) : default(T);

  string? s1 = GetDefault<string>(false);
  Assert.IsNull(s1);
  string? s2 = GetDefault<string>(true);
  Assert.IsNull(s2);

  int? d1 = default(int);
  Assert.AreEqual(d1, 0);
  int? d2 = default(int?);
  Assert.IsNull(d2);

  int? n1 = GetDefault<int>(false);
  Assert.AreEqual(n1, 0);
  int? n2 = GetDefault<int>(true);
  Assert.AreEqual(n2, 0); // Expected default(int?), i.e. Nullable<int> with no value.

  int? n4 = GetDefault<int?>(false);
  Assert.IsNull(n4);
  int? n5 = GetDefault<int?>(true);
  Assert.IsNull(n5);
}


To see why this isn't possible, try replacing T with a value type:

protected int ValueOrDefault<int>(IDataReader reader, int ordinalId)
        {  
  Type t = typeof(reader.GetValue(ordinalId));
    if (t.IsValueType){
        //Struct. How do I return null?
    } else { 
        //Class
        //just return  null
        return  default(int);
    }
}

If the return type is int, you can't return null because it's not a valid value. The type of T would have to be nullable in the first place, in which case default(T) works.


You can use just return default without (T) at the end. C# 7.1 or above.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜