开发者社区> 问答> 正文

C#中的数组如何部分实现IList <T>?

如您所知,C#中的数组实现IList 以及其他接口。尽管不知何故,他们在没有公开实现Count属性的情况下执行此操作IList 。数组只有一个Length属性。

这是C#/。NET违反其关于接口实现的规则的公然示例还是我错过了一些东西?

展开
收起
保持可爱mmm 2020-02-08 11:45:05 471 0
1 条回答
写回答
取消 提交回答
  • 如您所知,C#中的array实现IList ,以及其他接口

    好吧,是的,不是,不是。这是.NET 4框架中Array类的声明:

    [Serializable, ComVisible(true)] public abstract class Array : ICloneable, IList, ICollection, IEnumerable, IStructuralComparable, IStructuralEquatable { // etc.. } 它实现System.Collections.IList,而不是 System.Collections.Generic.IList <>。不能,数组不是通用的。通用IEnumerable <>和ICollection <>接口也是如此。

    但是CLR可以动态创建具体的数组类型,因此可以从技术上创建实现这些接口的数组类型。但是事实并非如此。请尝试以下代码,例如:

    using System; using System.Collections.Generic;

    class Program { static void Main(string[] args) { var goodmap = typeof(Derived).GetInterfaceMap(typeof(IEnumerable )); var badmap = typeof(int[]).GetInterfaceMap(typeof(IEnumerable )); // Kaboom } } abstract class Base { } class Derived : Base, IEnumerable { public IEnumerator GetEnumerator() { return null; } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } } 对于具有“找不到接口”的具体数组类型,GetInterfaceMap()调用失败。但是对IEnumerable <>的强制转换可以正常工作。

    这是鸭子般的嘎嘎打字。正是这种类型的输入产生了一种错觉,即每个值类型都源自从Object派生的ValueType。就像值类型一样,编译器和CLR都具有数组类型的特殊知识。编译器会看到您尝试转换为IList <>的尝试,并说“好吧,我知道该怎么做!”。并发出castclass IL指令。CLR对此没有任何问题,它知道如何提供可用于基础数组对象的IList <>实现。它具有否则隐藏的System.SZArrayHelper类的内置知识,该类实际上是实现这些接口的包装。

    您所询问的Count属性看起来并不像每个人都声称的那样明显地没有做到这一点:

    internal int get_Count<T>() {
        //! Warning: "this" is an array, not an SZArrayHelper. See comments above
        //! or you may introduce a security hole!
        T[] _this = JitHelpers.UnsafeCast<T[]>(this);
        return _this.Length;
    }
    

    是的,您当然可以称该评论为“违反规则” :)否则,它很方便。而且隐藏得非常好,您可以在SSCLI20(CLR的共享源分发)中进行检查。搜索“ IList”以查看发生类型替换的位置。实际运行中最好的地方是clr / src / vm / array.cpp,GetActualImplementationForArrayGenericIListMethod()方法。

    与CLR中允许为WinRT(又称为Metro)编写托管代码的语言投影中发生的情况相比,CLR中的这种替换相当温和。几乎所有核心​​.NET类型都在那里被替换。例如,IList <>映射到IVector <>,这是一个完全不受管的类型。COM本身是替代品,不支持泛型类型。

    好吧,那是看幕后发生的事情。这可能是非常不舒服,陌生和陌生的海洋,并且地图的尽头有龙。使地球平坦并为托管代码中实际发生的事情制作不同的图像非常有用。这样就可以将其映射到每个人最喜欢的答案。对于值类型,这不太好用(不要变异一个结构!),但是这个隐藏得很好。GetInterfaceMap()方法失败是我能想到的唯一的泄漏。

    2020-02-08 11:45:29
    赞同 展开评论 打赏
问答分类:
C#
问答地址:
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载