请考虑以下代码:

public class A
{
    public virtual Task<T?> M<T>()
    {
        throw new NotImplementedException();
    }
}

public class B : A
{
    public override Task<T?> M<T>()
    {
        throw new NotImplementedException();
    }
}

这将无法编译,并显示以下错误:

CS0508: 'B.M<T>()': return type must be 'Task<T?>' to match overridden member 'A.M<T>()'

然而,如果A是一个接口,类似的代码将不会有错误地编译. 该问题似乎不是特定版本的C#所特有的.

这背后的原因是什么?

推荐答案

Dr:可为空的引用类型在语言中引入了一些阻抗不匹配,相对于泛型是particularly.

这与可为空的引用类型有关.在可为空的引用类型存在之前,这段代码根本不会编译,因为T?没有意义.

我不认为think您可以用一种对T作为引用类型和T作为值类型都有意义的方式来定义它(除非底部的NOT NULL/DEFAULT版本这样做)……但如果你 Select 你想要的,你可以适当地限制T个:

将T约束为不可为Null的值类型:

public abstract class A
{
    public abstract Task<T?> M<T>() where T : struct;
}

public class B : A
{
    public override Task<T?> M<T>() where T : struct
    {
        throw new NotImplementedException();
    }
}

将T约束为引用类型:

public abstract class A
{
    public abstract Task<T?> M<T>() where T : class;
}

public class B : A
{
    public override Task<T?> M<T>() where T : class
    {
        throw new NotImplementedException();
    }
}

我确实同意这很奇怪--更奇怪的是notnull约束,其中您需要在覆盖上指定default约束:

public abstract class A
{
    public abstract Task<T?> M<T>() where T : notnull;
}

public class B : A
{
    public override Task<T?> M<T>() where T : default
    {
        throw new NotImplementedException();
    }
}

不幸的是,我坦率地承认,我并不完全理解这意味着什么.整个话题让人百思不得其解...

Csharp相关问答推荐

哪个nuget包含SecurityStampValidatorOptions

"virtual"修饰符对接口成员有什么影响?

通过条件列表删除/更新EF Core 7中的实体的有效方法

如何在C#中实现非抛出`MinBy`?

用于管理System.Text.Json中的多态反序列化的自定义TypeInfoResolver

记录类型';==运算符是否与实现IEquatable<;T&>;的类中的';equals&>方法执行等价比较?

如何更改新创建的实例的变量?

MSI无法将快捷方式添加到启动文件夹

在使用AWS SDK for.NET时,如何判断S3是否已验证我的对象的校验和?

EF Core 7-忽略模型绑定中的虚拟属性

毛伊岛.NET 8图片不再适合按钮

Linq SELECT的多条指令

如何在C# WinForm控件中使用Windows 10/11的黑暗主题?

Xamarin.Forms项目中缺少MainPage.xaml

在使用.NET EF Core DbContext属性之前,是否应使用null判断

如何获取我在SQL中输入的值

异步等待,如何在Windows窗体中使用它们?

使用多个身份验证方案时引发NullReferenceException

Dapper出错-无法将对象作为参数传递到Execute方法中

从C#程序可靠地运行Mercurial&S和HG状态