"Item"属性与索引器

3
我已阅读过有关具有索引器和名为“Item”的属性的类的答案,但它们并没有解释为什么我可以拥有一个具有多个索引器的类,它们都创建Item属性和get_Item/set_Item方法(当然工作正常,因为它们是不同的重载),但我不能拥有一个显式的Item属性。
考虑以下代码:
namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
        }

        public int this[string val]
        {
            get
            {
                return 0;
            }
            set
            {
            }
        }

        public string this[int val] //this is valid
        {
            get
            {
                return string.Empty;
            }
            set
            {
            }
        }

        public int Item { get; set; } //this is not valid
    }
}

对于两个索引器,创建了四种方法:

Int32 get_Item(String val)
Void set_Item(String val, Int32 value)
String get_Item(Int32 val)
Void set_Item(Int32 val, String value)

我希望您的属性能够创建。
Int32 get_Item()
Void set_Item(Int32 value)

这些重载通常是可以接受的,但不知何故编译器却不允许我创建这样的属性。

请注意,我不需要一种重命名索引器等的方法,这已经知道了 - 我需要一个解释。此答案:https://dev59.com/hm435IYBdhLWcg3w9FLi#5110449并没有解释为什么我可以有多个索引器。


我怀疑如果你将Item属性的返回类型更改为除了intstring之外的其他类型,它会编译通过,但事实并非如此。看起来编译器不允许在class/struct中声明索引器时拥有显式的Item属性。谁知道为什么呢?这很奇怪。 - Dan
1个回答

4
由于相同的原因,以下代码也无法编译:
public class Test
{
    public int Foo
    {
        get;
        set;
    }

    public void Foo()
    {
        return;
    }
}

上述代码会报错"The type 'Test' already contains a definition for 'Foo'".虽然可以将其实现为一个Foo()方法和一个get_Foo()方法,但是命名方式是一个实现细节 - 在语言层面上,它是.Foo()和.Foo,由于并不是所有的语言都支持该方式,编译器认为这是一个错误。
同样地,其他语言可能不支持拥有相同名称的索引器和属性。因此,尽管您指出这个问题可以编译为get_Item()和get_Item(Int32),CLR设计师们还是选择不允许这种情况。尽管CLR可以被设计为允许这种情况,但在语言层面上可能不被支持,所以他们选择避免任何类似的问题。

好的,我明白你的意思,C#并不是唯一的编程语言。但是多个索引器呢?我发现很难理解如何更容易地实现多个索引器而不是索引器+属性... - Piotr Zierhoffer
CLR允许存在同名的两个方法。CLR也允许存在同名的两个索引器。但是,你所说的是“一个属性和一个索引器同名”,这在CLR中是不被允许的,因为CLR不能确定语言是否支持这种情况。正如我所解释的,CLR通常认为重载同一类型的“事物”(例如索引器)是可以的,但是将两种不同类型的事物(例如属性和索引器)命名为相同的名称是不可以的。 - Chris
2
@Chris:我不确定它是否符合ECMA 335的CLR限制。例如,在§I.10.3.2中,索引器和属性都被称为“属性”,并且“属性和方法只能基于其参数的数量和类型进行重载(...)”。通常的属性具有0个参数,而索引器具有多个参数。另一方面,你的例子的推理在那里得到了解释。所以我猜这更像是C#的限制。 - konrad.kruczynski
1
经过查看两个规范,似乎这是一个C#问题。CLR本身没有索引器的概念(它们只是带有参数的属性),get_Item()和get_Item(Int32)可以通过方法重载来实现。然而,根据C#规范,除非明确允许,否则两个东西不能具有相同的名称。方法重载是允许的;属性重载是允许的;索引器重载是允许的;构造函数重载是允许的。不允许其他任何组合(属性和属性、方法和构造函数、方法和属性、属性和索引器)。 - Chris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接