[英]Why I can't use T? as a generic parameter in C#
I use .NET
5 in .NET Core
Console Application.我在
.NET Core
控制台应用程序中使用.NET
5。 The following code can't be compiled:以下代码无法编译:
public class NullableClass<T?>
{
}
The error is:错误是:
Error CS1003 Syntax error, ',' expected.
错误 CS1003 语法错误,“,”预期。
It doesn't matter whether I use any constraint.我是否使用任何约束都没有关系。
But this code compiles:但这段代码编译:
[return: MaybeNull]
public static T? Find<T>(IEnumerable<T?> sequence, Func<T?, bool> predicate)
{
foreach (var element in sequence) {
if (predicate(element)) return element;
}
return default(T?);
}
When I declare Find<T?>
I have the same error.当我声明
Find<T?>
我有同样的错误。
What don't I understand here?我在这里不明白什么?
If you want T
to be a nullable reference type, you should use a generic constraint for that:如果您希望
T
成为可为空的引用类型,则应为此使用泛型约束:
where T : class?
哪里T:上课?
The type argument must be a reference type, either nullable or non-nullable.类型参数必须是引用类型,可以为空或不可为空。 This constraint applies also to any class, interface, delegate, or array type.
此约束也适用于任何类、接口、委托或数组类型。
public class NullableClass<T> where T : class?
{
// code here
}
Note the question mark is a part of the constraint - there's also a constraint for class
(without the question mark) meaning "reference type", and in c# 8 or higher meaning "non-nullable reference type".请注意,问号是约束的一部分 -
class
(没有问号)也有一个约束,表示“引用类型”,在 c# 8 或更高版本中表示“不可为空的引用类型”。
You are confused about where types can be used.您对可以使用类型的位置感到困惑。
You are not supposed to use/write a type here:您不应该在此处使用/编写类型:
public class NullableClass< >
^^^
or here:或在这里:
public static T? Find< >(IEnumerable<T?> sequence, Func<T?, bool> predicate)
^^^
Syntactically, these places are the type_parameters
.从语法
type_parameters
,这些地方是type_parameters
。 You should declare type parameters there, rather than to use an existing type.您应该在那里声明类型参数,而不是使用现有类型。
public class Foo<List<int>>
makes no sense, right? public class Foo<List<int>>
没有意义,对吧?
From the language spec, this is the syntax for a class declaration :根据语言规范,这是类声明的语法:
class_declaration
: attributes? class_modifier* 'partial'? 'class' identifier type_parameter_list?
class_base? type_parameter_constraints_clause* class_body ';'?
;
type_parameter_list
is: type_parameter_list
是:
type_parameter_list
: '<' type_parameters '>'
;
type_parameters
: attributes? type_parameter
| type_parameters ',' attributes? type_parameter
;
type_parameter
: identifier
;
So really, type parameters are just identifiers, just like variable names in a variable declaration.所以实际上,类型参数只是标识符,就像变量声明中的变量名一样。
T?
is not an identifier.不是标识符。 In a
type_parameter_list
, you are just declaring what type parameters this class/method will have.在
type_parameter_list
,您只是声明该类/方法将具有哪些类型参数。
Now let's look at where types are used.现在让我们来看看其中使用的类型。
public static T? Find<T>(IEnumerable<T?> sequence, Func<T?, bool> predicate)
^^ ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^
These are all types, so you can use T?
这些都是类型,所以你可以使用
T?
in those places.在那些地方。 The method return type is obviously a type, so you can use a type there.
方法返回类型显然是一个类型,所以你可以在那里使用一个类型。 The
<>
I marked above are part of a type, so they are type_argument_list
s, not type_parameter_list
s.我在上面标记的
<>
是类型的一部分,所以它们是type_argument_list
s,而不是type_parameter_list
s。 You can use types in type_argument_list
s:您可以在
type_argument_list
使用类型:
type_name
: namespace_or_type_name
;
namespace_or_type_name
: identifier type_argument_list?
| namespace_or_type_name '.' identifier type_argument_list?
| qualified_alias_member
;
type_argument_list
: '<' type_arguments '>'
;
type_arguments
: type_argument (',' type_argument)*
;
type_argument
: type
;
If you want to allow both nullable and non-nullable reference types to be used as the type argument for the type parameter T
, use the class?
如果要允许可空引用类型和不可空引用类型都用作类型参数
T
的类型参数,请使用class?
constraint : 约束:
class NullableClass<T> where T: class? { ... }
Upvote Sweeper, if you want to use a nullable type, you don't need to have the ? Upvote Sweeper,如果你想使用可空类型,你不需要有 ? on the definitions, ie
在定义上,即
class Program
{
static void Main(string[] args)
{
int?[] valueList = new int?[] { 1, null, 3, 4, 5, null };
int? val = NullableClass<int?>.Find(valueList, new Func<int?, bool>(test));
}
public static bool test(int? testMe)
{
// Do something productive here
if (testMe != null && testMe % 2 == 0)
return true;
return false;
}
}
class NullableClass<T> {
public static T Find<T>(IEnumerable<T> sequence, Func<T, bool> predicate)
{
foreach (var element in sequence)
{
if (predicate(element)) return element;
}
return default(T);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.