具有默认参数的索引器

3

我知道这不是一个真实世界的问题,但我想知道:在没有反射/技巧的情况下,是否可以访问具有所有默认参数的索引器?

例如如何调用:

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

不显式提供参数怎么办?

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

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

2个回答

6
为什么编译器不会警告我代码没有意义?
因为实际上它是有意义的,只是在C#中不支持。例如,在COM中,支持使用无参数索引的默认属性。而C#是一种允许你实现COM服务器的语言。非常容易做到,只需应用[ComVisible(true)]属性即可。在C#中使用COM服务器也非常受欢迎,Office互操作就是一个常见的例子。
这种摩擦存在,因为这样的属性存在显著问题。语法糖非常甜美,但像任何糖果一样,它可能导致蛀牙。当你在脚本语言中使用这样的属性时,存在一个令人讨厌的语法歧义。
Dim obj As New Foo
obj = Nothing

这里的意图是什么?应该将 对象 分配为 Nothing 吗?还是应该分配默认属性为 Nothing?这两者都是完全合法的,编译器无法确定哪个最好。对于 Visual Basic 语言(VBScript、VBA、VB6),这种歧义是通过向语言添加一个额外的关键字来解决的。如果指的是对象,则应使用 Set,如果指的是默认属性,则应使用 Let 或 nothing 进行分配。这让许多刚开始从脚本编程入手的初学者感到困扰,“对象”的概念对他们来说并不是很清晰。当然,这也很容易出错,这是一个重大的错误产生器。
这个问题对交互操作核心也产生了非常不利的影响,COM 属性可以有两个设置器,PropPut 和 PropPutRef。这是在 IDispatch::Invoke() 方法中看到的东西。.NET 语言结束了这一点,这不仅因为 CLI 不允许此类情况,而且他们坚持认为默认属性必须有一个参数。现在编译器是没有歧义的,它可以确定是否打算进行对象赋值,因为这不使用索引器参数。
C# 团队特别难以说服这个改变是应该回溯的,他们绝对讨厌歧义,他们最初坚持认为只能有 一个 索引属性,而这个属性 必须 是默认属性,并且只有一个参数。索引器。他们最终在版本4时屈服了,太多编写 Office 交互代码的程序员要求改进。但是它只被带到了必要的程度,在交互场景中可以使用,但在 C# 代码中仍然不允许。你得用困难的方式调用 get_Item(),或者当然可以不写这样的代码...

0

问题在于,如果你仔细想想,这是完全有道理的。

整个问题基于从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)

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

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


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