C# 泛型接口协方差

2023-12-22

我不确定这里发生了什么,但我使用以下代码收到编译器错误:

namespace SO
{
    interface IUser<PostType>
    {
        PostType Post { get; set; }
    }

    interface IPost<UserType>
    {
        UserType User { get; set; }
    }

    class User : IUser<Post>
    {
        //Implementation
    }

    class Post : IPost<User>
    {
        //Implementation
    }

    class SomeOtherClass
    {
        // Compiler Error: Cannot implicitly convert type 'SO.User' to
        // 'SO.IUser<SO.IPost<SO.User>>'. An explicit conversion exists 
        // (are you missing a cast?)
        IUser<IPost<User>> user = new User();

        //Works Fine
        IUser<Post> user = new User();
    }
}

为什么我会收到错误如果Post是一个子类型IPost<User>?我知道在这种情况下我可以使用User代替IUser<IPost<User>>,但我想知道为什么这不起作用。


我将尝试用简单的例子来解释它。假设你还有一个类实现IPost<User>:

class PicturePost : IPost<User>
{
    // Implementation
}

那么这段代码将无法编译:

    IUser<Post> user = new User();
    user.Post = new PicturePost();

Because user.Post属于具体类Post这是不兼容的PicturePost(他们是兄弟姐妹)。

然后想象一下您的问题中的那一行已成功编译:

    // C# compiler is so kind today and it compiled this.
    IUser<IPost<User>> user = new User();

Since user.Post现在将是类型IPost<User>你可能会编写这样的行:

    IUser<IPost<User>> user = new User();
    user.Post = new PicturePost();

他们将完美编译,但第二行将失败运行时错误!这是因为实际类型user.Post is Post not IPost or PicturePost.

因此,为了实现类型安全,C#编译器会在有机会编写此类代码时禁止编译。为了保证你不会写出这样的代码,Post属性应该是只读的:

interface IUser<PostType>
{
    PostType Post { get; } // No setter, this is readonly.
}

现在你将无法编写邪恶的代码,并且所有用法Post就其接口而言将是类型安全的,因为您可以get它,然后完美地分配给其接口的变量。

但这还不够,要告诉编译器你的接口是轻量级的,你需要显式指定你的类型参数只是out(你可以使用它,但你不能将它传递进去)。因此,具有以下接口的实现(注意out关键字),您的代码将编译:

interface IUser<out PostType>
{
    PostType Post { get; } // No setter, this is readonly.
}

    // Both lines compile!
    IUser<IPost<User>> user = new User();
    IUser<Post> user1 = new User();

希望我保持简单,同时没有错过要点:)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# 泛型接口协方差 的相关文章

  • 为什么这个 Web api 控制器不并发?

    我有一个 Web API 控制器 里面有以下方法 public string Tester Thread Sleep 2000 return OK 当我调用它 10 次 使用 Fiddler 时 我预计所有 10 次调用都会在大约 2 秒后
  • 尝试了解使用服务打开对话框

    我已经阅读了有关使用 mvvm 模式打开对话框的讨论 我看过几个使用服务的示例 但我不明白所有部分如何组合在一起 我发布这个问题寻求指导 以了解我应该阅读哪些内容 以更好地理解我所缺少的内容 我将在下面发布我所拥有的内容 它确实有效 但从我
  • C# 方法重载决策不选择具体的泛型覆盖

    这个完整的 C 程序说明了这个问题 public abstract class Executor
  • 转换 const void*

    我有一个函数返回一个const void 我想用它的信息作为char 我可以将它投射为 C 风格的罚款 char variable但是当我尝试使用reinterpret cast like reinterpret cast
  • 如何在类文件中使用 Url.Action() ?

    如何在 MVC 项目的类文件中使用 Url Action Like namespace 3harf public class myFunction public static void CheckUserAdminPanelPermissi
  • 前向声明类型和“已声明为类类型的非类类型”

    我对以下代码有问题 template
  • MVC3中设置下拉列表中的所选项目

    我必须为视图中的下拉列表设置所选项目 但它不起作用 View div class editor label Html LabelFor model gt model Gender div div class editor field Htm
  • extern 声明和函数定义都在同一文件中

    我只是浏览了一下gcc源文件 在gcc c 我发现了类似的东西 extern int main int char int main int argc char argv 现在我的疑问是extern是告诉编译器特定的函数不在这个文件中 但可以
  • 语音识别编程问题入门

    所以 你们可能都看过 钢铁侠 其中托尼与一个名为贾维斯的人工智能系统进行交互 演示剪辑here http www youtube com watch v Go8zsh1Ev6Y 抱歉 这是广告 我非常熟悉 C C 和 Visual Basi
  • 如何在 C# Designer.cs 代码中使用常量字符串?

    如何在 designer cs 文件中引用常量字符串 一个直接的答案是在我的 cs 文件中创建一个私有字符串变量 然后编辑 Designer cs 文件以使用此变量 而不是对字符串进行硬编码 但设计者不喜欢这样抛出错误 我明白为什么这行不通
  • 如何使用 Regex.Replace 从字符串中删除数字?

    我需要使用Regex Replace从字符串中删除所有数字和符号 输入示例 123 abcd33输出示例 abcd 请尝试以下操作 var output Regex Replace input d string Empty The d标识符
  • C++中判断unicode字符是全角还是半角

    我正在编写一个终端 控制台 应用程序 该应用程序应该包装任意 unicode 文本 终端通常使用等宽 固定宽度 字体 因此要换行文本 只需计算字符数并观察单词是否适合一行并采取相应的操作 问题是 Unicode 表中的全角字符在终端中占用了
  • 在 C# 中检查 PowerShell 执行策略的最佳方法是什么?

    当你跑步时Get ExecutionPolicy在 PowerShell 中 它得到有效的执行政策 https learn microsoft com en us powershell module microsoft powershell
  • 是否使用 C# 数据集? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我对 C 中的数据集概念有点困惑 编码 ASP NET 站点 但这并不重要 在我的阅读中 我了解到它们 本质上 用作我的应用程序和我的
  • C++ - 多维数组

    处理多维数组时 是否可以为数组分配两种不同的变量类型 例如你有数组int example i j 有可能吗i and j是两种完全不同的变量类型 例如 int 和 string 听起来您正在寻找 std vector
  • 将二变量 std::function 转换为单变量 std::function

    我有一个函数 它获取两个值 x 和 y 并返回结果 std function lt double double double gt mult double x double y return x y 现在我想得到一个常量 y 的单变量函数
  • 将函数参数类型提取为参数包

    这是一个后续问题 解包 元组以调用匹配的函数指针 https stackoverflow com questions 7858817 unpacking a tuple to call a matching function pointer
  • 比较:接口方法、虚方法、抽象方法

    它们各自的优点和缺点是什么 接口方法 虚拟方法 抽象方法 什么时候应该选择什么 做出这一决定时应牢记哪些要点 虚拟和抽象几乎是一样的 虚方法在基类中有一个实现 可以选择重写 而抽象方法则没有 并且must在子类中被覆盖 否则它们是相同的 在
  • WPF DataGrid / ListView 绑定到数组 mvvm

    我们假设你有 N 个整数的数组 表示行数的整数值 在模型中 该整数绑定到视图中的 ComboBox Q1 如何将数组 或数组的各个项目 绑定到 DataGrid 或 ListView 控件 以便 当您更改 ComboBox 值时 只有那么多
  • 在 Win32 控制台应用程序中设置光标位置

    如何在 Win32 控制台应用程序中设置光标位置 最好 我想避免制作句柄并使用 Windows 控制台功能 我花了整个早上沿着那条黑暗的小巷跑 它产生的问题比它解决的问题还要多 我似乎记得当我在大学时使用 stdio 做这件事相对简单 但我

随机推荐

  • 无法生成临时类(结果=1)。错误CS0030:

    我正在尝试使用贝宝快速结账https www sandbox paypal com wsdl PayPalSvc wsdl https www sandbox paypal com wsdl PayPalSvc wsdl 当我打电话使用时
  • 在for循环中运行replace()方法?

    已经很晚了 我一直在尝试编写一个简单的脚本 将点云数据重命名为工作格式 我不知道我做错了什么 因为底部的代码工作正常 为什么for循环中的代码不起作用 它将其添加到列表中 但它只是没有被替换功能格式化 抱歉 我知道这不是调试器 但我真的很困
  • 如何使用 Gmail 中的标签来识别单个邮件而不是已由脚本处理的线程

    使用 google 邮件脚本 我尝试使用 API 将带有某些标签的新电子邮件上传到我们的 CRM 我无法检查邮件是否已上传 因此我必须在邮箱中为之前已处理过的邮件应用标签 不幸的是 谷歌脚本只允许您在线程级别添加或检查标签 由于新消息可以在
  • 使用 sqlplus 检索大型 clob 数据

    如何使用 sqlplus 将大 clob 数据从表中完全检索到标准输出 有一种方法可以使用特定于语言的数据库 API 来完全获得它 但是当我尝试纯粹使用 sqlplus 来获取它时 我遇到了几个问题 例如 输出缓冲区太小 最大 4000 字
  • Xamarin:应用程序未安装问题

    当我在 Android 移动设备上以调试模式安装应用程序时 它似乎已安装 但是 在签署应用程序并发布后 它并未安装在我的手机上 释放模式 它说 应用程序未安装 我尝试了一些方法但无法解决这个问题 我还用另一个密钥库进行了测试 但仍然无法安装
  • 将匿名侦听器与 C# 和垃圾收集中的事件分离

    假设我有一个名为 Dialog 的类 它扩展了 Form 对话框上有一个文本框和一个 确定 按钮 当用户单击 确定 时 文本框值将通过事件返回 public class Dialog Form public delegate void on
  • 命令替换中的 Heredoc:引号或括号不平衡时出错(bash 和 zsh)

    考虑以下用于打印单引号的混淆脚本 该脚本适用于ksh bin ksh echo cat lt
  • Hive Utf-8 编码支持的字符数?

    您好 实际上问题如下 我想要插入到 hive 表中的数据包含拉丁单词 并且采用 utf 8 编码格式 但 hive 仍然无法正确显示 Actual Data 数据插入到hive中 我将表的编码更改为 utf 8 下面的 hive DDL 和
  • FFMPeg 异常 setDataSource 失败:状态 = 0xFFFFFFFF

    我有 175 个 mp4 文件 当我处理从索引 0 到索引 65 或 66 的文件时 出现异常 java lang IllegalArgumentException setDataSource failed status 0xFFFFFFF
  • 使用NSVisualEffectView时如何添加按钮

    我使用创建了一个窗口NSVisualEffectView获得模糊和圆角 喜欢here https stackoverflow com q 42762856 7517228 问题是当我有时我在窗口中看不到我的按钮NSVisualEffectV
  • 未捕获的类型错误:$this.text 不是函数

    这段代码中的第二条语句 var this this children div submenu1 children a subtile 0 title this text name this attr node val 产生这个错误 Unca
  • Java TreeMap 相当于 C# 吗?

    我咨询过的大多数地方都说使用SortedList 但问题是我正在移植的程序实际上使用了重复的键 按顺序区分 这是TreeMap允许的 但SortedList不允许 有什么建议吗 Does 排序字典 http msdn microsoft c
  • ASIHTTPRequest 的 XML 解析器

    我可以使用什么 XML 解析器库最适合解析 ASIHTTPRequest 响应中的 XML 响应字符串 这也很容易设置并且很容易理解 确实需要立即得到项目结果 Thanks 按照这个 如何在 Objective C 中解析 XML http
  • 如何使用 volley 库 android 执行简单的异步任务

    如您所知 Google 发布了一个新的库 Volley 来管理基于 HTTP 协议的网络请求 但是如果我想使用这个库连接到 mysql db 目前我正在使用异步任务来进行网络调用 如何实现volley库来执行异步任务 任何链接或示例 抱歉英
  • 获取 std::future 的状态

    是否可以检查是否std future完成与否 据我所知 唯一的方法就是打电话wait for持续时间为零并检查状态是否为ready或者没有 但是有更好的方法吗 你是对的 除了打电话wait until对于过去的时间 相当于 没有更好的方法
  • jQuery 将类的一部分与 hasClass 匹配

    我有几个带有 project 0 9 类的 div div class project1 div div class project2 div div class project3 div div class project4 div 我想
  • 为 Eclipse 本身(平台)启用控制台日志记录

    我的 JVM JRE 和 Eclipse 本身有问题 我正在 Windows 8 1 下使用 IBM JVM 运行 Juno 版本 当我尝试从 https P2 URL 访问 安装新软件时 收到以下错误消息 javax net ssl SS
  • Android Q - 未经批准连接wifi

    我正在开发一个自动连接到 Wifi 的应用程序 您会在下面找到我的代码 效果很好 class MainActivity AppCompatActivity override fun onCreate savedInstanceState B
  • 从 ElasticBeanstalk EC2 到 Redis (ElastiCache) 的连接失败

    我们使用 ElasticBeanstalk 来设置一些 Node js 环境 目前 我们使用 Redis 作为会话存储 它设置在 ElastiCache 中 当我 ssh 进入 EC2 实例并 netcat Redis 存储时 我可以确认网
  • C# 泛型接口协方差

    我不确定这里发生了什么 但我使用以下代码收到编译器错误 namespace SO interface IUser