3

I've read the answers for Class with indexer and property named "Item", but they do not explain why can I have a class with multiple indexers, all of them creating Item property and get_Item/set_Item methods (of course working well, as they are different overloads), but I cannot have an explicit Item property.

Consider the code:

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
    }
}

For two indexers there are four methods created:

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

I'd expect my property to create

Int32 get_Item()
Void set_Item(Int32 value)

These overloads are generally acceptable, but somehow the compiler won't let me create such a property.

Please note that I don't need a way to rename the indexer etc, this is known - I need an explanation. This answer: https://stackoverflow.com/a/5110449/882200 doesn't explain why I can have multiple indexers.

Community
  • 1
  • 1
Piotr Zierhoffer
  • 5,005
  • 1
  • 38
  • 59
  • I suspected that if you were to change the return type of the `Item` property to something other than `int` and `string`, it would compile, but that is not the case. It looks like the compiler doesn't allow you to have an explicit `Item` property if you declare indexers in your `class`/`struct`. Who knows why? That's strange. – Dan Jun 20 '13 at 14:19

1 Answers1

4

For the same reason that the following won't compile:

public class Test
{
    public int Foo
    {
        get;
        set;
    }

    public void Foo()
    {
        return;
    }
}

The above results in "The type 'Test' already contains a definition for 'Foo'". Although these could be implemented as a Foo() method and a get_Foo() method, the naming is an implementation detail - at the language level, it's .Foo() and .Foo and since not all languages would support that, the compiler considers it an error.

Similarly, other languages may not support having an indexer and a property with the same name. So, although as you point out this could be compiled as get_Item() and get_Item(Int32), the CLR designers nevertheless chose not to allow it. Although the CLR could have been designed to allow this, it may not be supported at the language level, so they chose to avoid any such issues.

Chris
  • 4,661
  • 1
  • 23
  • 25
  • Ok, I get your point, that C# is not the only language out there. But what about multiple indexers? I find it hard to understand how is it easier to implement multiple indexers and NOT indexer + property... – Piotr Zierhoffer Jun 20 '13 at 14:28
  • "Two methods with the same name" is allowed by the CLR. "Two indexers with the same name" is allowed by the CLR. What you're talking about is "One property and one indexer with the same name", and that is not allowed by the CLR because they didn't want to assume that the language would support that. As I tried to explain, the CLR generally takes the stance that overloading two of the same type of 'thing' (e.g. indexer) is okay, but naming two *different* types of thing (e.g. a property and an indexer) with the same name is not okay. – Chris Jun 20 '13 at 14:31
  • 2
    @Chris: I'm not sure about it being CLR restriction according to ECMA 335. For example, in §I.10.3.2 indexers and properties are referred to by the same name "properties" and "Properties and methods can be overloaded based only on the number and types of their parameters (...)". And usual property has this number 0, indexer - more than zero. On the other hand reasoning for your example is covered there. So I guess this is rather C# restriction. – konrad.kruczynski Jun 20 '13 at 14:41
  • 1
    Having gone and checked both specs, it does look to be a C# matter. The CLR itself has no concept of indexers (they're just properties with parameters), and get_Item() and get_Item(Int32) would be allowed by method overloading. By the C# specification, however, two things can't have the same name *unless explicitly allowed*. Method overloading is allowed; property overloading is allowed; indexer overloading is allowed; and constructor overloading is allowed. No other combination (property & property, method & constructor, method & property, property & indexer) is allowed. – Chris Jun 20 '13 at 15:21