【问题标题】:Indexer named "Item" required by interface but not possible to implement?接口需要名为“Item”但无法实现的索引器?
【发布时间】:2019-01-29 04:58:58
【问题描述】:

我正在尝试在 ESPRIT api 中实现一个类的接口,该接口需要一个名为“Item”的索引器。 (我猜该接口来自 VB.NET,但我没有源代码。)显然“Item [index]”索引器默认情况下由编译器自动生成,但我收到以下错误:

我意识到[System.Runtime.CompilerServices.IndexerName("Item")] 是多余的;它只是为了明确地证明 Item 已生成并且错误仍然存​​在。

尝试实现 public ToolBarControl Item[int index] '会破坏课堂其余部分的所有内容。

Edit1:第三个屏幕截图显示IToolBar.this,但我确实尝试了IToolBar.Item,结果如上所述。

看起来我不是第一个请求命名迭代器的人,但我认为生成的命名索引器应该满足要求。 https://github.com/dotnet/csharplang/issues/471

如何实现这个索引器来满足接口?


注意:为了完整性、未来故障排除和回答 cmets 中提出的问题,我进行了以下编辑,但我已经知道此特定实例的解决方案正在实施 get_Item(int index),如已接受的答案中所述。

Edit2:回答“Visual Studio 的建议是什么?”如您所见,它在替换之前就知道Index 将出错,因为Item 上没有定义Index 参数(我已经对此进行了测试,它确实失败了。)其他两个都不是自动实施工作的选项。

Edit3:在对象浏览器中,IToolBar 内部,Item[int] 定义为:

【问题讨论】:

  • 您正在使用的这个自定义库是否有 API 文档?
  • 删除您自己的代码后,当您将鼠标悬停在 Esprit.Toolbar 上时,Visual Studio 建议执行什么?
  • 这个缺失成员的接口规范是什么?
  • 你确定this[]的返回类型是'ToolBarControl'?
  • 如果找不到文档,请在反汇编程序中打开参考,看看它具体在寻找什么。 @Neil 可能是对的,它可能期待来自索引器的“对象”或“IToolbarControl”。

标签: c# .net vb.net interface indexer


【解决方案1】:

问题是没有用于声明命名索引器的有效 C# 语法,因此您无法使用 C# 满足该接口。有几个在 C# 中实现命名索引器的请求,所有这些请求都被 C# 语言团队忽略或完全拒绝。他们似乎不想在 C# 中实现此功能。也许如果他们稍后改变主意,您可能会得到机会。

目前我认为解决此问题的唯一方法是创建一个 VB.NET 库,其中包含一个实现接口并充当您自己的类的包装器或基类的类。

【讨论】:

    【解决方案2】:

    C# 可以从带有get_Item 的接口满足那个 .Item 'indexer'。这是因为在 IL 编译期间如何生成 Property/Index getter 和 setter。

    这是CLI Specification中的描述:

    I.10.4 命名模式

    对于属性:

    通过确定其 getter 方法返回的类型和 getter 参数的类型(如果有)。 然后,创建了两个方法,其名称基于 属性的名称和这些类型。 对于下面的示例,我们定义了两个属性: 名称 不带参数并返回 System.String,而 Item 带 System.Object 参数 并返回一个 System.Object。 Item 被称为索引属性,这意味着它需要 参数,因此可以通过它向用户显示为带有索引的数组。

    PropertyGet, used to read the value of the property
       Pattern: <PropType> get_<PropName> (<Indices>)
       Example: System.String get_Name ();
       Example: System.Object get_Item (System.Object key);
    PropertySet, used to modify the value of the property
       Pattern: void set_<PropName> (<Indices>, <PropType>)
       Example: void set_Name (System.String name);
       Example: void set_Item (System.Object key, System.Object value); 
    

    因此,您应该能够满足索引器实现它的条件,如下所示:

    public class ManagedEspritToolbar : Esprit.Toolbar
    {
        public ToolbarControl get_Item(int index) => Toolbar[index];
    }
    

    为了对此进行测试,您可以在 VB.NET 中创建一个简单的接口:

    Public Interface IVBNetInterface
        Property Item(index As Integer) As String
    End Interface
    

    然后在 C# 中的新类上实现接口。请注意,当允许 IDE 自动实现接口时,它默认为 get_Item/set_Item 访问器:

    public class CSharpClass : IVBNetInterface
    {
        public string get_Item(int index)
        {
            throw new NotImplementedException();
        }
    
        public void set_Item(int index, string Value)
        {
            throw new NotImplementedException();
        }
    }
    

    读取接口生成的 IL 可以确认这种行为:


    VB.NET 的默认属性呢?

    在 VB.NET 中,有一个 Default 属性装饰器,它本质上是在类上声明索引器的机制:

    Public Interface IVBNetInterface
        Default Property Item(index As Integer) As String
    End Interface
    

    当这在 VB.NET 类/接口上正确实现时,标准 C#this[int] 索引实现将起作用。因此,get_Item 解决方法只有在默认属性正确应用于目标索引属性时才真正需要。请注意添加 System.Reflection.DefaultMemberAttribute 属性后,在应用此功能后调查 IL 代码:


    改进使用:

    要绕过使用Default修饰符编写的底层类/接口,您可以显式实现接口索引器,这允许在类上公开传统的C#风格的索引器:

    public class CSharpClass : IVBNetInterface
    {
        public string this[int index]
        {
            get => throw new NotImplementedException();
            set => throw new NotImplementedException();
        }
    
        #region IVBNetInterface
    
        string IVBNetInterface.get_Item(int index) => this[index];
    
        void IVBNetInterface.set_Item(int index, string value) => this[index] = value;
    
        #endregion
    }
    

    如果您希望通过典型索引器推断类的使用,同时仍满足基础 Interface.Item 要求,这可能是首选方法。

    【讨论】:

    • 我将get_Item 实现为public ToolBarControl get_Item(int index) =&gt; ToolBar.Item[index]; 并且它(奇怪的是)满足了Item[int] get 的要求。想要在答案顶部添加一个 TLDR 简介,基本上说明 get_Item(int index) 可以满足接口的 Item 要求?
    • @Still.Tony,我使用过另一个用 VB.NET 编写的第三方库,我注意到一些类似的行为。如果您有 IL 反汇编程序,则可能值得查看 IToolbar 以查看底层代码。也许在某处用“Esprit”更新您的问题,以便其他人可以找到它。
    猜你喜欢
    • 1970-01-01
    • 2017-12-19
    • 1970-01-01
    • 1970-01-01
    • 2012-10-26
    • 2019-01-07
    • 2014-04-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多