我有一个通用接口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>
答案 0 :(得分:2)
我认为这个问题与this post中发生的事情非常相似。
请注意,T? where T : class
和T? where T : struct
在CLR中的表示方式非常不同。前者只是CLR类型T
。 CLR中没有单独的类型来区分T
和T?
。 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
约束,则会引发相同的错误。您需要使用class
或struct
约束来指定该类型是什么。您无需指定notnull
,因为结构始终是可空的,并且启用了可空的引用类型,类也是如此。
只需添加where T:class
或where 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 Types的The 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。