List 来自 MSDN 的声明:
public class List<T> : IList<T>, ICollection<T>,
IEnumerable<T>, IList, ICollection, IEnumerable
Reflector 给出了类似的图片。 List 是否真的实现了所有这些(如果是,为什么)?
我检查过:
interface I1 {}
interface I2 : I1 {}
interface I3 : I2 {}
class A : I3 {}
class B : I3, I2, I1 {}
static void Main(string[] args)
{
var a = new A();
var a1 = (I1)a;
var a2 = (I2)a;
var a3 = (I3)a;
var b = new B();
var b1 = (I1) b;
var b2 = (I2)b;
var b3 = (I3)b;
}
它编译。<>
[更新]:
伙计们,据我所知,所有的回复都是:
class Program
{
interface I1 {}
interface I2 : I1 {}
interface I3 : I2 {}
class A : I3 {}
class B : I3, I2, I1 {}
static void I1M(I1 i1) {}
static void I2M(I2 i2) {}
static void I3M(I3 i3) {}
static void Main(string[] args)
{
var a = new A();
I1M(a);
I2M(a);
I3M(a);
var b = new B();
I1M(b);
I2M(b);
I3M(b);
Console.ReadLine();
}
}
会报错,但编译和运行没有任何错误。为什么?
>
最佳答案
更新:这个问题是my blog entry for Monday April 4th 2011的基础.感谢您提出很好的问题。
让我把它分解成许多更小的问题。
Does
List<T>really implement all those interfaces?
是的。
Why?
因为当接口(interface)(比如 IList<T>)继承自接口(interface)(比如 IEnumerable<T>)时,派生程度更高的接口(interface)的实现者也需要实现派生程度更低的接口(interface)。这就是接口(interface)继承的意思;如果您履行更多派生类型的契约(Contract),那么您还需要履行更少派生类型的契约(Contract)。
So a class is required to implement all the methods of all the interfaces in the transitive closure of its base interfaces?
没错。
Is a class that implements a more-derived interface also required to state in its base type list that it is implementing all of those less-derived interfaces?
没有。
Is the class required to NOT state it?
没有。
So it's optional whether the less-derived implemented interfaces are stated in the base type list?
是的。
Always?
几乎总是:
interface I1 {}
interface I2 : I1 {}
interface I3 : I2 {}
I3是否声明继承自I1是可选的。
class B : I3 {}
I3 的实现者需要实现 I2 和 I1,但他们不需要明确声明他们正在这样做。这是可选的。
class D : B {}
派生类不需要重新声明它们实现了基类的接口(interface),但允许这样做。 (这种情况比较特殊;详情请见下文。)
class C<T> where T : I3
{
public virtual void M<U>() where U : I3 {}
}
对应于 T 和 U 的类型参数是实现 I2 和 I1 所必需的,但对于 T 或 U 上的约束来说,声明这一点是可选的。
在分部类中重述任何基接口(interface)总是可选的:
partial class E : I3 {}
partial class E {}
E 的后半部分可以声明它实现了 I3 或 I2 或 I1,但不是必须这样做。
OK, I get it; it's optional. Why would anyone unnecessarily state a base interface?
也许是因为他们认为这样做可以使代码更易于理解和更易于 self 记录。
或者,也许开发人员将代码编写为
interface I1 {}
interface I2 {}
interface I3 : I1, I2 {}
然后意识到,哦,等一下,I2 应该继承自 I1。为什么要进行该编辑然后要求开发人员返回并将 I3 的声明更改为不包含明确提及 I1?我认为没有理由强制开发人员删除冗余信息。
Aside from being easier to read and understand, is there any technical difference between stating an interface explicitly in the base type list and leaving it unstated but implied?
通常没有,但在一种情况下可能会有细微差别。假设你有一个派生类 D,它的基类 B 已经实现了一些接口(interface)。 D 通过 B 自动实现这些接口(interface)。如果您在 D 的基类列表中重新声明接口(interface),则 C# 编译器将执行接口(interface)重新实现。细节有点微妙;如果您对其工作原理感兴趣,那么我建议您仔细阅读 C# 4 规范的第 13.4.6 节。
Does the
List<T>source code actually state all those interfaces?
没有。实际的源代码说
public class List<T> : IList<T>, System.Collections.IList
Why does MSDN have the full interface list but the real source code does not?
因为MSDN是文档;它应该为您提供尽可能多的信息。将文档全部集中在一个地方比让您搜索十个不同的页面以找出完整的接口(interface)集要清楚得多。
Why does Reflector show the whole list?
Reflector 只有元数据可以使用。由于放入完整列表是可选的,Reflector 不知道原始源代码是否包含完整列表。最好宁可获得更多信息。同样,Reflector 试图通过向您显示更多信息而不是隐藏您可能需要的信息来帮助您。
BONUS QUESTION: Why does
IEnumerable<T>inherit fromIEnumerablebutIList<T>does not inherit fromIList?
一个整数序列可以被视为一个对象序列,通过装箱每个从序列中出来的整数。但是整数的读写列表不能被视为对象的读写列表,因为您可以将字符串放入对象的读写列表中。一个IList<T>不需要履行 IList 的全部契约(Contract), 所以它不从它继承。
关于c# - 为什么(真的吗?)List<T> 实现所有这些接口(interface),而不仅仅是 IList<T>?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4817369/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为
它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput
我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?