为什么不能在 C# 中将 null 转换为类型参数 T?
Why cannot convert null to type parameter T in c#?
我正在将一堆代码从 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 的 return 为 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;
}
它不会编译并出现此错误:
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>'
我需要能够拥有相同的功能,否则它会破坏很多代码。我错过了什么?
由于T
既可以是引用类型也可以是值类型,所以如果T是值类型,returning null
将不满足。你应该 return:
return default(T);
来自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.
更新 (2021-09-27)
使用 C# 7.1 的新语法,您可以 return:
return default;
在 C# 的情况下,您必须使用 default(T),如果您只是 return T 而不是 T,它将 return 0 而不是 Nothing 或 Null?
现在如果 VB.net 根据你的例子你说你 return 没有什么是正确的但是你是否尝试检查 return 该函数的值。
喜欢
Dim c = <<your class object>>.FindItem("test",Nothing); // you have to pass valid values.
如果你检查 C 的值,那么它是 0 而不是什么都没有。
现在谈谈在 MSIL 级别发生的事情。
当您编译 VB.net 代码并检查其 MSIL 时。你会发现 initobj !T 这是 default(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>()
我正在将一堆代码从 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 的 return 为 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;
}
它不会编译并出现此错误:
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>'
我需要能够拥有相同的功能,否则它会破坏很多代码。我错过了什么?
由于T
既可以是引用类型也可以是值类型,所以如果T是值类型,returning null
将不满足。你应该 return:
return default(T);
来自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.
更新 (2021-09-27)
使用 C# 7.1 的新语法,您可以 return:
return default;
在 C# 的情况下,您必须使用 default(T),如果您只是 return T 而不是 T,它将 return 0 而不是 Nothing 或 Null?
现在如果 VB.net 根据你的例子你说你 return 没有什么是正确的但是你是否尝试检查 return 该函数的值。
喜欢
Dim c = <<your class object>>.FindItem("test",Nothing); // you have to pass valid values.
如果你检查 C 的值,那么它是 0 而不是什么都没有。
现在谈谈在 MSIL 级别发生的事情。
当您编译 VB.net 代码并检查其 MSIL 时。你会发现 initobj !T 这是 default(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>()