为什么无法在 c# 中将 null 转换为类型参数 T



我正在将一堆代码从 VB 转换为 C#,并且遇到了方法问题。 这种VB方法效果很好:

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

它允许为 T 返回 Nothing(null)。

C# 等效项不起作用:

public T FindItem(string p_propertyName, object p_value)
{
  Int32 index = FindIndex(p_propertyName, p_value);
  if (index >= 0) {
    return this[index];
  }
  return null;
}

它不会编译此错误:

类型"T"

必须是不可为空的值类型,才能在泛型类型或方法'System.Nullable<T>'中将其用作参数"T"

我需要能够具有相同的功能,否则它会破坏很多代码。 我错过了什么?

由于T可以是引用类型或值类型,因此返回null将不满足T是否为值类型。您应该返回:

return default(T);

从链接默认关键字:

给定参数化类型 T 的变量 t,语句 t = null 仅在 T 是引用类型且 t = 0 仅适用于数值类型而不适用于结构时才有效。解决方案是使用默认关键字,该关键字将为引用类型返回 null,为数值类型返回零。对于结构,它将返回初始化为零或 null 的结构的每个成员,具体取决于它们是值类型还是引用类型。对于可为 null 的值类型,default 返回 System.Nullable,该值像任何结构一样初始化。

更新 (2021-09-27)

使用 C# 7.1 中的新语法,您可以返回:

return default;

在 C# 的情况下,您必须使用 default(T),如果您只返回 T 而不是 T?,它将返回 0 而不是 Nothing 或 Null。

现在,如果按照您的示例 VB.net,您说返回的任何内容都是正确的,但是您是否尝试检查该函数的返回值。

喜欢

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

如果您检查 C 的值,那么它是 0 而不是什么都没有。

现在来谈谈 MSIL 级别发生的事情。

编译时,VB.net 代码并检查其 MSIL。 你会发现 伊尼托布 ! T 和这是默认值 (T) 的指令。它会自动执行此操作。因此,如果您从 C# 调用 VB.net 库,那么它也可以工作。

您可以使用此方法

public static IList<int> ToIntList(this object values)
        {
            //try to convert using modified ChangeType which handles nullables
            try
            {
                if (values == null) return new List<int>();
                var charValues = values.ToType<string>();
                return charValues.Split(',').Select(n => Convert.ToInt32(n)).ToList();
            }
            //if there is an exception then get the default value of parameterized type T
            catch (Exception)
            {
                return new List<int>();
            }
        }
internal static object ChangeType(object value, Type conversionType)
        {
            if (conversionType == null)
            {
                throw new ArgumentNullException("conversionType");
            } 
            if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition() == typeof (Nullable<>))
            {
                if (value == null)
                {
                    return null;
                } 
                var nullableConverter = new NullableConverter(conversionType);
                conversionType = nullableConverter.UnderlyingType;
            }
            return Convert.ChangeType(value, conversionType);
        }

像这样使用

userVar.ToType<int>()
userVar.ToType<string>()

最新更新