Question

I know this is not a real world issue, but I wonder: can you access an indexer with all default parameters without reflection/tricks?

For example how to call:

public int this[string val="", int sth=5]
{
    get
    {
         return 0;
    }
    set
    {
    }
}

without providing parameters explicitly?

I'd think about something like myobject[], but it's obviously incorrect.

Why doesn't the compiler warn me about not making any sense?

Was it helpful?

Solution

Why doesn't the compiler warn me about not making any sense?

Because it does actually make sense, just not in C#. A default property that's indexed with no arguments is readily supported in COM for example. And C# is a language that lets you implement COM servers. Very easy to do, just apply the [ComVisible(true)] attribute. Using COM servers in C# is very popular as well, Office interop is the common example.

This friction exists because there's a significant problem with such properties. The syntax sugar is very sweet, but like any sugar it can produce rotten teeth. There's a nasty syntax ambiguity when you use such a property in, say, a scripting language:

Dim obj As New Foo
obj = Nothing

What was intended here? Should the object be assigned Nothing? Or should the default property be assigned Nothing? Both are perfectly legitimate, the compiler can't figure out which one is best. For the Visual Basic languages (VBScript, VBA, VB6), this ambiguity was resolved by adding an extra keyword in the language. You are supposed to use Set when you meant the object, Let or nothing to assign the default property. This has bedeviled many aspiring programmers that got their start in scripting, the notion of an "object" just isn't very clear to them. And of course is very easy to oops, it is a major bug generator.

This problem has had a very detrimental effect on the interop core as well, COM properties can have two setters, PropPut and PropPutRef. Something you see back in the IDispatch::Invoke() method. .NET languages put an end to it, not in the least because the CLI doesn't allow this, they insist that a default property must have an argument. Now it is unambiguous to the compiler, it can tell if the object assignment was intended since that doesn't use the indexer argument.

The C# team was particular difficult to convince that this should be changed back, they absolutely hate ambiguity, as well they should. They originally insisted that there can be only one indexed property and that this property must be the default property and have only one argument. The indexer. They finally caved at version 4, too many programmers writing Office interop code clamored for an improvement. But took it only as far as necessary, okay in interop scenarios but still not allowed in C# code. You'll have to call get_Item() the hard way. Or of course just not write code like this...

OTHER TIPS

The point is, if you think about it, that it DOES make perfect sense.

The whole issue is based on some habits taken from C++. If you have default parameters, they go in the end of the parameter list. It's the same way in C#.

The main difference between C++ and C# is that in the latter you can access method parameters by names! Unlike in C++, where you have to provide all of the parameters in the order as they come in the method's declaration, in C# it's perfectly legal to:

class Sth
{
    public int this[string val="", int sth=5]
    {
        get
        {
             return 0;
        }
        set
        {
        }
    }

    public Sth()
    {
        var i = this[sth: 6];
    }
}

This notation would not be possible in standard C++ .

So even that we have default values for every parameter of the indexer, this could be meaningful if we'd want to run it using one (or a subset) of the parameters.

This, automatically, brings us to a second question: what about an indexer with only one parameter with default value?

class Sth
{
    public int this[int sth=5]
    {
        get
        {
             return 0;
        }
        set
        {
        }
    }
}

The world remains sane. While we actually cannot use the indexer in "the proper way" (i.e. without reflection or some other hacky mechanism), we get a warning. On Mono (and probably .NET as well) it looks like this:

Warning CS1066: The default value specified for optional parameter 'sth' will never be used (CS1066)

We actually can't call it without providing an explicit value for the parameter.

The whole problem would be a lot easier to solve if I'd think about a single-parameter indexer first. But, well, I did not. ;-)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top