我想知道将
Nullable<int>
类型传递给接受 T?
(另一种 Nullable<int>
类型)的泛型方法的行为是什么。这是有问题的代码:
int? myNullableParameter = 8;
MyGenericMethod(myNullableParameter);
void MyGenericMethod<T>(T? parameter)
{
//Do Something with parameter
Console.WriteLine($"{parameter}");
}
由于编译良好,所以这里存在混乱。我将 myNullableParameter 的类型设置为
Nullable<int>
。然后我将此类型作为 Nullable<T>
传递到参数化泛型方法中。但是,参数的类型也是 T?
,它从编译器解析为 Nullable<T>
。那么它是Nullable<Nullable<int>>
吗?或者编译器是否只是忽略第二个Nullable<T>
并将参数保留在方法内作为Nullable<int>
?
谢谢!
(我的回答假设您使用的是 C# 9.0 或更高版本)
我想知道将
类型传递给接受Nullable<int>
(另一种T?
类型)的泛型方法的行为是什么。Nullable<int>
我认为你有一个误解;从这里看来,您似乎认为/理解/相信,当 unconstrained 泛型类型
T
注释为 T?
时,这意味着 C#+CLR 会将 值类型 T
类型参数处理为 Nullable<T>
和 引用类型 T
类型参数为 [AllowNull]/[MaybeNull]
,包括某种方式编组
自 C# 9.0 起,泛型类型语法
T?
(当 T
不受约束时)仅意味着:
T
是引用类型,那么此时,这个T是可能为空,即[AllowNull]/[MaybeNull]
”T
是Nullable<U>
,那么此时,T
可能是null
”
nullableStruct.HasValue == false
T
(not a T?
)出现在同一范围内,则表示非null
Nullable<T>
(即 value.HasValue == true
)。T
是值类型(而不是 Nullable<U>
),则此 T 是 不可为空的 T
值类型”。
void AcceptsAllegedlyNullableT<T>( T? nullableTee, T notNullableTee ) // <-- T is unconstrained here
{
// etc
}
:不可空引用类型:如果我们指定 T = String
,则
tee
参数保留其 ?
注释,因此它变为 String?
。
所以我们有 void AcceptsAllegedlyNullableT<String>( String? nullableTee, String notNullableTee )
nullableTee
接受一个 Maybe-null
String
参考,而 notNullableTee
不接受。
:可空引用类型:如果我们指定 T = String?
,则
nullableTee
参数 won't为
String??
,但注释会折叠为相同的 String?
类型。
所以我们有 void AcceptsAllegedlyNullableT<String?>( String? nullableTee, String? notNullableTee )
tee
接受一个 Maybe-null
String
引用 - 并且 notNullableTee
实际上是可以为空的。
:(不可为 null)-值类型:如果我们指定 T = Int32
,那么
?
类型 上的 tee
注释是一个谎言,因为它的 静态类型 仍然存在Int32
而不是
Nullable<Int32>
。所以我们有
void AcceptsAllegedlyNullableT<Int32>( Int32 nullableTee, Int32 notNullableTee )
nullableTee
不能接受
Nullable<Int32>
,尽管有?
注释,但至少notNullableTee
再次被准确命名......(我无意中听到人们说,鉴于此,?
default(T)
”而不是“也许-null
” - 但那些人生活在泡沫中)。
:可空值类型:如果我们指定 T = Nullable<Int32>
(又名
Int32?
或 int?
),那么 ?
类型上的 nullableTee
注释仍然是谎言,因为所有 T
参考文献变为 Nullable<T>
,而不仅仅是 T?
。
所以我们有
void AcceptsAllegedlyNullableT<Nullable<Int32>>( Nullable<Int32> nullableTee, Nullable<Int32> notNullableTee )
notNullableTee
是一个void Main()
{
AcceptsAllegedlyNullableT<String>( null, "a" );
AcceptsAllegedlyNullableT<String?>( null, null );
AcceptsAllegedlyNullableT<Int32>( 123, 456 );
AcceptsAllegedlyNullableT<Int32?>( null, null );
}
static void AcceptsAllegedlyNullableT<T>( T? nullableTee, T notNullableTee ) // <-- T is unconstrained here
{
Console.WriteLine( "------------------------------------------" );
Type staticType = typeof(T);
Type runtimeType1 = nullableTee ?.GetType();
Type runtimeType2 = notNullableTee?.GetType();
Console.WriteLine( "Runtime value of nullableTee : " + ( nullableTee ?.ToString() ?? "null" ) );
Console.WriteLine( "Runtime value of notNullableTee: " + ( notNullableTee?.ToString() ?? "null" ) );
Console.WriteLine( "Static-type of nullableTee : " + typeof(T) .FullName );
Console.WriteLine( "Static-type of notNullableTee: " + typeof(T?).FullName );
Console.WriteLine( "Runtime-type of nullableTee : " + ( nullableTee ?.GetType().FullName ?? "null" ) );
Console.WriteLine( "Runtime-type of notNullableTee: " + ( notNullableTee?.GetType().FullName ?? "null" ) );
Console.WriteLine( "------------------------------------------" );
}
控制台输出:
Runtime value of nullableTee : null
Runtime value of notNullableTee: a
Static-type of nullableTee : System.String
Static-type of notNullableTee: System.String
Runtime-type of nullableTee : null
Runtime-type of notNullableTee: System.String
------------------------------------------
------------------------------------------
Runtime value of nullableTee : null
Runtime value of notNullableTee: null
Static-type of nullableTee : System.String
Static-type of notNullableTee: System.String
Runtime-type of nullableTee : null
Runtime-type of notNullableTee: null
------------------------------------------
------------------------------------------
Runtime value of nullableTee : 123
Runtime value of notNullableTee: 456
Static-type of nullableTee : System.Int32
Static-type of notNullableTee: System.Int32
Runtime-type of nullableTee : System.Int32
Runtime-type of notNullableTee: System.Int32
------------------------------------------
------------------------------------------
Runtime value of nullableTee : null
Runtime value of notNullableTee: null
Static-type of nullableTee : System.Nullable`1[[System.Int32, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]
Static-type of notNullableTee: System.Nullable`1[[System.Int32, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]
Runtime-type of nullableTee : null
Runtime-type of notNullableTee: null
------------------------------------------