【问题标题】:Why cannot convert null to type parameter T in c#?为什么不能在c#中将null转换为类型参数T?
【发布时间】:2015-03-23 20:49:13
【问题描述】:

我正在将一堆代码从 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”@

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

【问题讨论】:

    标签: c# vb.net vb.net-to-c#


    【解决方案1】:

    由于T 既可以是引用类型也可以是值类型,所以如果T 是值类型,返回null 将不满足。你应该返回:

    return default(T);
    

    来自链接default keyword

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

    更新(2021-09-27)

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

    return default;
    

    【讨论】:

    • @RobertBeaubien: default(T) 将返回 null 如果 T 是引用类型,请检查链接。
    • @RobertBeaubien:如果你真的想返回null,你需要使用where T: class来约束T是引用类型,但是你应该注意到如果T是值类型,这种方式将不起作用跨度>
    • @RobertBeaubien VB.Net 的 Nothing 相当于 C# 的 default(),而不是 nullmsdn.microsoft.com/en-us/library/0x9tb07z.aspx
    • “引用类型”是使用class 定义的类型。使用structStructure 定义“值类型”。只有引用类型可以是空值。 (魔法类型 Nullable(of T) 除外。)
    • VB 关键字 Nothing 在 C# 中拼写为 default(T)。他们在所有情况下都做同样的事情。 (另请注意,Nothing 与 Null 不同。所有 Null 都是 Nothing,但并非所有 Nothing 都是 Null。)
    【解决方案2】:

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

    现在,对于 VB.net,根据您的示例,您说您返回 Nothing 是正确的,但您是否尝试检查该函数的返回值。

    喜欢

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

    如果你检查 C 的值,那么它是 0,而不是什么。

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

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

    【讨论】:

    • 是的,VB 中没有任何东西是默认值。引用类型的默认值为 null。所以它适用于可空值类型。所以在 C# 中返回 default(T) 而不是 Nothing 是合适的。
    【解决方案3】:

    你可以用这个方法

    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>()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      • 2018-02-10
      • 2012-03-08
      • 2015-12-20
      • 1970-01-01
      • 1970-01-01
      • 2020-07-25
      相关资源
      最近更新 更多