c# - 数组索引器和任何其他对象索引器有什么区别

标签 c# arrays data-structures indexer

考虑以下两种数据类型:

class C
{
    public int I { get; set; }
}

struct S
{
    public int I { get; set; }
}

让我们尝试在列表中使用它们,例如:

var c_list = new List<C> { new C { I = 1 } };
c_list[0].I++;

var s_list = new List<S> { new S { I = 1 } };
s_list[0].I++; // (a) CS1612 compilation error

如预期的那样,(a) 行出现编译错误: CS1612 Cannot modify the return value of 'List<UserQuery.S>.this[int]' because it is not a variable .这很好,因为实际上我们试图修改 S 的临时副本,这是给定上下文中的 r 值。

但让我们尝试对数组做同样的事情:

var c_arr = new[] { new C { I = 1 } };
c_arr[0].I++;

var s_arr = new[] { new S { I = 1 } };
s_arr[0].I++; // (b)

而且..这行得通。

但是

var s_arr_list = (IList<S>) s_arr;
s_arr_list[0].I++;

不会像预期的那样编译。

如果我们查看生成的 IL,我们会发现以下内容:

IL_0057:  ldloc.1     // s_arr
IL_0058:  ldc.i4.0    // index
IL_0059:  ldelema     UserQuery.S // manager pointer of element

ldelema将数组元素的地址加载到计算堆栈的顶部。 fixed 预期会出现这种行为数组和不安全指针。但是对于安全上下文来说,这有点出乎意料。为什么数组有一个特殊的不明显的情况?为什么没有为其他类型的成员实现相同行为的选项?

最佳答案

数组访问表达式被归类为变量。您可以分配给它,通过引用传递它等。索引器访问单独分类...在分类列表中(C# 5 规范第 7.1 节)

  • An indexer access. Every indexer access has an associated type, namely the element type of the indexer. Furthermore, an indexer access has an associated instance expression and an associated argument list. When an accessor (the get or set block) of an indexer access is invoked, the result of evaluating the instance expression becomes the instance represented by this (§7.6.7), and the result of evaluating the argument list becomes the parameter list of the invocation.

将此视为类似于字段和属性之间的区别:

 public class Test
 {
     public int PublicField;
     public int PublicProperty { get; set; }
 }

 ...

 public void MethodCall(ref int x) { ... }

 ...

 Test test = new Test();
 MethodCall(ref test.PublicField); // Fine
 MethodCall(ref test.PublicProperty); // Not fine

从根本上说,索引器是一对方法(或单个方法),而数组访问为您提供一个存储位置。

请注意,如果您一开始没有使用可变结构,您将看不出这种方式的区别——我强烈建议您根本不要使用可变结构。

关于c# - 数组索引器和任何其他对象索引器有什么区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31790651/

相关文章:

c# - 如何使用 LINQ 将两个或多个集合合并为一个集合

java - 元素切换时遇到问题

java - 创建 OBJECT ARRAYS 并使用它们时出现 NullPointerException

php - 应用配置信息 : MySQL, XML 或 PHP 类?

无法从单链表中删除元音

c# - 如何获取字符串并作为数据类型的选择返回

c# - ODataController 返回 HTTP 406 Not Acceptable

c# - SignalR 核心 - GlobalHost.DependencyResolver.Register

arrays - 带开关元件的最长子阵列

data-structures - 看起来像保龄球瓶的数据结构的名称是什么?