即使参数没有null约束,也会收到有关nullable类型参数的错误

时间:2019-10-04 04:07:08

标签: c# nullable c#-8.0 nullable-reference-types

我有一个通用接口IDataAdapter<T>;接口的实现者应该能够从数据源中读取具有Guid ID的POCO。 IDataAdapter<T>有一个方法Read(Guid id),我想返回一个T?,其中null表示在数据源中找不到匹配项。但是,即使在T : notnull上有约束IDataAdapter<T>,尝试定义此方法也会产生错误CS8627: A nullable type parameter must be known to be a value type or non-nullable reference type. Consider adding a 'class', 'struct', or type constraint.,即使T约束为{{ 1}}?

代码(应该在带有notnull的C#8环境中):

<Nullable>enable</Nullable>

3 个答案:

答案 0 :(得分:2)

我认为这个问题与this post中发生的事情非常相似。

请注意,T? where T : classT? where T : struct在CLR中的表示方式非常不同。前者只是CLR类型T CLR中没有单独的类型来区分TT? T?在C#中只是增加了C#编译器的编译时间检查。另一方面,后者由CLR类型Nullable<T>表示。

因此,让我们考虑一下您的方法:

T? Read (Guid id);

在CLR中应如何表示?什么是退货类型?编译器不知道T是引用类型还是值类型,因此编译器无法确定方法签名应为:

T Read (Guid id);

或:

Nullable<T> Read (Guid id);

答案 1 :(得分:0)

如果查看Nullable Struct的文档,您会发现它必须是struct

public struct Nullable<T> where T : struct

我相信您需要将T约束为struct

interface IA<T> where T : struct
{
    T? Read(Guid id);
    // Or Nullable<T> Read(Guid id);
}


class A : IA<int>
{
    public int? Read(Guid id) { Console.WriteLine("A"); return 0; }
}

顺便说一句。您能否举一个例子说明您要使用该类使用什么类型?

为什么不只使用where T: class并返回T(甚至根本没有约束)?

interface IA<T> where T : class
{
    T Read(Guid id);
}

答案 2 :(得分:0)

如果不使用notnull约束,则会引发相同的错误。您需要使用classstruct约束来指定该类型是什么。您无需指定notnull,因为结构始终是可空的,并且启用了可空的引用类型,类也是如此。

只需添加where T:classwhere T:struct

引用类型

如果添加class约束,例如:

#nullable enable

interface IDataAdapter<T>       
    where T:class
{
    T? Read (Guid id); // error CS8627

    void Something(T input);
}

class StringAdapter:IDataAdapter<string>
{
    public string Read(Guid id)=>id.ToString();

    public void Something(string input){}
}

以下呼叫将产生警告:

var adp=new StringAdapter();
string? x=null;
adp.Something(x);  //CS8604: Possible null reference argument ....

值类型

如果参数可为空,则使用struct创建IntAdapter会导致编译错误:

interface IDataAdapter<T>       
    where T:struct
{
    T? Read (Guid id); // error CS8627

    void Something(T input);
}


class IntAdapter:IDataAdapter<int>
{
    public int? Read(Guid id)=>id.ToString().Length;

    public void Something(int input){}
}

void Main()
{

    var adp=new IntAdapter();
    int? x=null;
    adp.Something(x);  //CS1503: Cannot convert from int? to int
}

这是因为编译生成的方法期望使用int?而不是int

说明

原因是编译器必须在每种情况下生成完全不同的代码。对于一堂课,它不需要做任何特别的事情。对于一个结构,它必须生成一个Nullable

这在Try out Nullable Reference TypesThe issue with T?部分中进行了解释:

  

可空值类型和可空引用类型之间的区别以这种模式出现:

     

void M<T>(T? t) where T: notnull

     

这将意味着该参数是T的可为空的版本,并且T被约束为非null。如果T是一个字符串,则M的实际签名为M([NullableAttribute] T t),但是如果T为一个int,则M为M(Nullable t)。这两个签名本质上是不同的,并且这种差异是无法调和的。

     

由于可空引用类型和可空值类型的具体表示之间存在此问题,是否使用T?还必须要求您将T约束为class或struct。