【问题标题】:Covariance, contravariance, and an ILookup-style interface协变、逆变和 ILookup 风格的界面
【发布时间】:2011-11-19 20:01:42
【问题描述】:

如果一个人正在设计像ILookup 这样的界面(为简单起见,假设它只是ICheckIfContained,因此项目值的类型无关紧要),相对于第一个,理想的方差类型是什么参数?

检查ICheckIfContained<Animal> 是否包含特定的Cat 是一种自然操作,并且在正常的逆变规则下是类型安全的。

检查ICheckIfContained<Cat> 是否包含特定的Animal 在正常的逆变规则下不是类型安全的,但会是自然且明确定义的(如果有问题的Animal 不是@987654328 @,正确的行为是 ICheckIfContained 说它不包含有问题的动物)。

检查ICheckIfContained<Cat> 是否包含特定的Dog 不会特别有用(答案总是“否”),但答案会很明确。请注意,此场景中的答案与前一个不同,可以静态确定。

一种方法是让ICheckIfContained 成为非通用接口,并简单地接受Object 类型的参数。然而,在列表只包含单一类型的结构的情况下,这似乎相当低效。另一方面,如果它是一个泛型接口,那么编译器将无法允许它在协变场景中使用(传入一个其声明类型是预期类型的​​父级的参数,这样传入的对象可能或可能不是预期的类型)。

在编译器可以确认所有内容都是相同类型的情况下,有没有什么好的模式可以提高泛型的效率,同时仍然允许检查父类型的对象是否在集合中的一般情况行为子类型?

【问题讨论】:

  • 有了这种代表,我希望您知道如何格式化问题中的代码。学习使用反勾号`。
  • 啊,谢谢。我知道backtick 在 cmets 中工作,但我并没有想到它也可以在问题/答案中工作,因为问题使用 HTML(如 )来表示 bold i> 在答案中使用标点符号(星号,在粗体的情况下)处理。我认为在问题/答案中应该使用 之类的东西,尽管 TT 标记在这里特别不起作用。

标签: .net generics covariance contravariance


【解决方案1】:

我认为你做不到。能够将其静态检查为 false 肯定会很有效,但只有在编译器确切知道此方法执行哪种操作时,才能优化将 Dog 传递给 Contains(cat)

如果您的Contains 实际上是Add 怎么办?编译器不理解方法名称。

【讨论】:

  • “包含”的想法是它可以被任何类型合法地调用,而像“添加”这样的东西不能。这种情况有点像 Object.Equals/IComparable.Equals 的情况,只是 ICheckIfContained 经常使用一个函数来比较两个不同的对象,这与比较一个对象与自身的情况略有不同。跨度>
  • 是的,那么当类型不匹配时,如何向编译器指定它应该静态返回false?我理解这个想法,但编译器不理解。
  • 举个简单的例子,如果可以基于类或结构约束重载泛型,并且 ICheckIfContained 包含开放的泛型方法 Contains<U>(U thing) where U:structContains<U>(U thing) where U:class 方法,则 T 是一个类的实现可以让Contains<U>(U thing) where U:struct 的实现总是返回 False。如果可以将泛型类型限制为 Object 以外的类,那么对于 T 是结构的实现也可以这样做。
  • 我认识到在没有泛型的情况下拳击的必要性;鉴于存在泛型,我发现装箱有点可疑(在需要将结构存储在期望类类型的对象中的情况下,可以使用泛型 Holder 类)。在某些情况下,像 String.Format 这样的方法接受自动装箱参数会很有帮助,但我宁愿要求这些方法明确地请求自动装箱行为,而不是允许装箱发生。
猜你喜欢
  • 1970-01-01
  • 2016-11-03
  • 2015-02-09
  • 2012-04-06
  • 1970-01-01
  • 2011-02-09
  • 1970-01-01
  • 2012-12-03
相关资源
最近更新 更多