简体   繁体   English

为什么我不能用T? 作为 C# 中的泛型参数

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM