【问题标题】:Why isn't a type constraint of "where T : object" compiling in C# 8为什么不在 C# 8 中编译“where T : object”的类型约束
【发布时间】:2019-09-09 16:06:28
【问题描述】:

根据https://github.com/dotnet/csharplang/blob/master/proposals/csharp-8.0/nullable-reference-types-specification.md object 现在是一个有效的类型约束。

可空引用类型可用作通用约束。此外,对象现在作为显式约束有效。没有约束现在就等同于一个对象?约束(而不是对象),但是(与之前的对象不同)对象?不作为显式约束被禁止。

我认为这应该可以正确编译,但 Visual Studio 不允许我编译它。

public class A<T> where T : object { }

我是误读了这个还是 VS 或 C#8 的问题?

更新

我正在尝试为缓存定义一个接口。

public interface IDataCache
{
    void Put<T>(string key, T value) where T : notnull;
    T? Get<T>(string key) where T : notnull;
}

理想情况下,我不希望缓存空值,但我也不能保证缓存中会有一个值。有时我想缓存一个类,但有时它可能是一个整数。这可能实现还是我必须为每种情况制定单独的方法?

public interface IDataCache
{
    void Put<T>(string key, T value) where T : notnull;

    // This seems really nasty!
    T? GetClass<T>(string key) where T : class;
    T? GetStruct<T>(string key) where T : struct;
}

【问题讨论】:

  • "/proposals"“这是一项正在进行的工作 - 有几个部分缺失或不完整。”
  • “对象泛型类型约束”功能目前处于预览状态,目前“不受支持”。要使用预览功能,请使用“预览”语言版本。
  • @R.J.Dunnill 相反,C# 8 和 .NET Core 3 在过去几个月都获得了 Go Live 许可证,距离最终版本只有 2 周的时间。人们已经在生产中使用它。这是一个有效的问题 - 该功能是否适用于 C# 8?
  • 这是一个很好的问题——如何在泛型中指定可空性? C# 8 已经拥有 Go Live 许可证,因此它支持。该功能仍然存在,但语法不同
  • @Panagiotis Kanavos 这是 Visual Studio 2019 给我的错误文本。

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


【解决方案1】:

这是一个有效的问题,答案不是微不足道的。出于正当的原因,自从最初的提议以来,情况发生了很大变化。在其他地方使用object? 语法会导致混淆。

链接指向提案文档,而不是实际文档或规范。您可以在 C# 指南的 Nullable Reference Types 中找到文档。那里没有对通用约束的参考。 Constraints on type parameters 文章也没有提到 object?,但确实提到了 notnull 约束。

变化及其背后的原因在Try out Nullable Reference Types进行了解释。

常见情况:允许空值

这个:

public class A<T>
{
    T DoStuff(T input)
    {
        return input;
    }
}

接受任何结构或值类型,包括空类型。以下行不会产生任何警告:

var x=new A<string?>();

非空约束

您必须使用notnull 约束指定您想要的不可为空的类型:


public class A<T>
    where T:notnull
{
    T DoStuff(T input)
    {
        return input;
    }
}

现在使用string? 作为类型参数会产生警告:

警告 CS8714:类型“字符串?”不能用作泛型类型或方法“A”中的类型参数“T”。类型参数“字符串”的可空性?不匹配 'notnull' 约束。

T 的问题?

要使用 nullable 类型,您必须指定类型是类还是结构。其原因在介绍 NRT 的博客文章的 The issue with T? section 中进行了解释。 T? 意味着T 是不可为空的,那么T 是什么?类还是结构?编译器以不同的方式处理每种情况。使用结构,编译器将生成Nullable&lt;T&gt; 类型,而类由编译器魔术处理。

这段代码:

public class A<T>
{
    T? DoStuff(T input)
    {
        return input;
    }
}

会抛出编译器错误,而不仅仅是警告:

必须知道可空类型参数是值类型或不可空引用类型。考虑添加“类”、“结构”或类型约束。

添加class 约束并将string 作为类型参数传递不会产生任何错误或警告:

public class A<T>
    where T:class
{
    T? DoStuff(T input)
    {
        return input;
    }
}

var x=new A<string>();

【讨论】:

  • 感谢您的回复,我了解 T 的问题?虽然如果我理解正确,这会给我留下更多问题。我已经用我真正想要实现的目标更新了我原来的问题。
  • @jws305 如果你不想要nulls 为什么要返回 T?来自Get?返回null 以指定缺失值并不是一个好主意。这就是为什么许多收集方法有一个 TryGetTryXXX 方法返回 true 和输出变量中的实际值。另一种选择是从Get 返回一个值元组,例如(T,bool)。如果值缺失则返回(default,false),如果找到则返回(value,true)
  • 我想新的可为空引用类型的重点是避免使用 null 来指定缺失值。我将使用 TryGet 方法。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
  • 1970-01-01
  • 2015-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-21
相关资源
最近更新 更多