具有默认参数的索引器

时间:2013-06-21 07:29:15

标签: c# indexer default-parameters

我知道这不是一个真实世界的问题,但我想知道:您是否可以使用所有默认参数访问索引器而无需反射/技巧?

例如如何致电:

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

没有明确提供参数?

我会考虑像myobject[]这样的东西,但这显然是不正确的。

为什么编译器不警告我没有任何意义?

2 个答案:

答案 0 :(得分:6)

  

为什么编译器不警告我没有任何意义?

因为它确实有意义,只是不在C#中。例如,COM中很容易支持使用 no 参数索引的默认属性。 C#是一种允许您实现COM服务器的语言。很容易做到,只需应用[ComVisible(true)]属性即可。在C#中使用COM服务器也很受欢迎,Office互操作就是常见的例子。

这种摩擦存在是因为这些特性存在严重问题。语法糖非常甜,但像任何糖一样,它会产生腐烂的牙齿。当你在脚本语言中使用这样的属性时,会出现令人讨厌的语法歧义:

Dim obj As New Foo
obj = Nothing

这里打算做什么?是否应该为对象分配什么?或者应该为默认属性分配Nothing?两者都是完全合法的,编译器无法确定哪一个是最好的。对于Visual Basic语言(VBScript,VBA,VB6),通过在语言中添加额外的关键字来解决这种歧义。您应该在意味着对象时使用Set,允许或不提供默认属性。这已经困扰了很多有抱负的程序员,他们开始编写脚本,“对象”的概念对他们来说并不是很清楚。当然很容易哎呀,它是一个主要的bug生成器。

此问题对互操作核心也有非常不利的影响,COM属性可以有两个 setter,PropPut和PropPutRef。你在IDispatch :: Invoke()方法中看到的东西。 .NET语言终结了它,至少因为CLI不允许这样做,他们坚持默认属性必须有一个参数。现在它对编译器来说是明确的,它可以判断对象分配是否是预期的,因为它不使用索引器参数。

C#团队特别难以说服这应该改回来,他们绝对讨厌歧义,他们也应该这样做。他们最初坚持只有一个索引属性,并且此属性必须是默认属性,并且只有一个参数。索引器。他们最终屈服于第4版,太多编写Office互操作代码的程序员吵着要求改进。但是只在必要时才接受它,在互操作场景中没问题但在C#代码中仍然不允许。你必须用艰难的方式调用get_Item()。或者当然只是不写这样的代码......

答案 1 :(得分:0)

重点是,如果你仔细想想,那就完全有道理了。

整个问题基于C ++的一些习惯。如果您有默认参数,它们将位于参数列表的末尾。它与C#中的方式相同。

C ++和C#之间的主要区别在于,在后者中,您可以按名称访问方法参数! 与C ++不同,在C ++中,您必须按照方法声明中的顺序提供所有参数,在C#中,它完全合法:

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

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

这种符号在标准C ++中是不可能的。

因此,即使我们为索引器的每个参数都有默认值,如果我们想要使用一个(或子集)参数来运行它,这可能是有意义的。

这自动地给我们带来了第二个问题:只有一个参数具有默认值的索引器呢?

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

世界仍然健全。虽然我们实际上不能以“正确的方式”使用索引器(即没有反射或其他一些hacky机制),但我们会收到警告。在Mono上(也可能是.NET)它看起来像这样:

  

警告CS1066:为可选参数指定的默认值   永远不会使用'sth'(CS1066)

如果没有为参数提供显式值,我们实际上无法调用它。

如果我首先考虑单参数索引器,整个问题将更容易解决。但是,我没有。 ; - )