2

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

例如如何调用:

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

没有明确提供参数?

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

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

4

2 回答 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 or nothing 来分配默认属性。这困扰了许多开始编写脚本的有抱负的程序员,“对象”的概念对他们来说并不是很清楚。当然很容易 oops,它是一个主要的错误生成器。

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

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

于 2013-06-21T12:24:34.647 回答
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
        {
        }
    }
}

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

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

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

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

于 2013-06-21T07:29:14.540 回答