接口需要索引器“ Item”,但无法实现吗?

时间:2018-08-22 21:12:31

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

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

Errors

我意识到[System.Runtime.CompilerServices.IndexerName("Item")]是多余的;只是在这里可以清楚地证明产生了Item并且错误仍然存​​在。

尝试实现public ToolBarControl Item[int index]'会使类的其余部分陷入混乱。

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

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

如何实现该索引器以满足接口要求?


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

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

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

2 个答案:

答案 0 :(得分:4)

C#可以使用get_Item从接口中满足该.Item'索引器'。这是因为在IL编译期间如何生成Property / Index getter和setter。

CLI Specification中的描述如下:

  

I.10.4命名模式

     

对于属性:

     

通过确定其getter方法和   吸气剂参数的类型(如果有)。 然后,根据名称创建两个方法   属性的名称和这些类型。 在下面的示例中,我们定义了两个属性:名称   不带任何参数并返回System.String,而Item带一个System.Object参数   并返回一个System.Object。项称为索引属性,表示它需要   参数,因此对用户来说就像是一个带有索引的数组。

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确认此行为:

enter image description here


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解决方法仅在将Default属性未正确应用于目标索引属性时才真正有必要。一旦应用了IL代码,请注意在研究IL代码时添加了System.Reflection.DefaultMemberAttribute属性:

enter image description here


改善用法:

要避开用Default修饰符编写的基础类/接口 ,可以显式实现接口索引器,该接口索引器可在类上公开传统的C#样式索引器:< / p>

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要求,则这可能是首选方法。

答案 1 :(得分:0)

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

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