我正在尝试在ESPRIT api中实现一个类的接口,该接口需要一个名为“ Item”的索引器。 (我猜接口来自VB.NET,但我没有源代码。)显然,默认情况下,“ Item [index]”索引器是由编译器自动生成的,但出现以下错误:< / p>
我意识到[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
参数(我已经测试过了,它的确失败了。 )用于自动实施工作的其他两个选项都没有。
答案 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确认此行为:
在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
属性:
要避开用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库,该库具有一个实现接口并充当您自己类的包装器或基类的类。