索引器是属性的扩展版本吗?
3 回答
索引器允许类或结构的实例像数组一样被索引。索引器类似于属性,只是它们的访问器带有参数。
class SampleCollection<T>
{
// Declare an array to store the data elements.
private T[] arr = new T[100];
// Define the indexer, which will allow client code
// to use [] notation on the class instance itself.
// (See line 2 of code in Main below.)
public T this[int i]
{
get
{
// This indexer is very simple, and just returns or sets
// the corresponding element from the internal array.
return arr[i];
}
set
{
arr[i] = value;
}
}
}
// This class shows how client code uses the indexer.
class Program
{
static void Main(string[] args)
{
// Declare an instance of the SampleCollection type.
SampleCollection<string> stringCollection = new SampleCollection<string>();
// Use [] notation on the type.
stringCollection[0] = "Hello, World";
System.Console.WriteLine(stringCollection[0]);
}
}
这取决于观点,真的。
就 C# 而言,它们是两个正交的概念。一个类可能有零个或多个属性,也可能有零个或多个索引器。属性由它们的名称来区分,索引器由它们的参数类型重载(类似于方法)。它们的相似之处在于可以有一个 gettor、一个 settor 或两者都有,并且赋值运算符(包括复杂的运算符,例如+=
)知道如何处理它们。
从 CLS(和 VB)的角度来看,没有索引器之类的东西。只有属性,其中一些被索引,而另一些则没有。索引属性是您必须提供除接收器本身之外的附加值来读取值,以及接收器和新值来写入值的属性 - 附加值是索引。还有一个“默认属性”的概念——只有一组属性(都具有相同的名称,但不同的索引类型)可以是默认的。
从 CLR 的角度来看,属性本身只是一个名称,带有一个类型和一组与之关联的方法;它本身并没有任何意义。它只是显示在查找该名称的属性的访问器时在哪里可以找到方法。没有默认属性的概念。
现在要调和这三件事...
按照 CLS 约定,普通属性在 CLR 级别由与具有相应签名的方法关联的属性表示,一个用于 getter,一个用于 setter。Foo
对于type的属性T
,它们将是:
T get_Foo();
void set_Foo(T);
对于索引类型为I1
, I2
, ... 的索引属性:
T get_Foo(I1, I2, ...);
void set_Foo(I1, I2, ..., T);
表示一个默认属性,DefaultMemberAttribute
用于指定该属性的名称。
C# 通过将索引器表示为索引属性来协调其视图与 CLS 的视图。默认情况下,它使用Item
所有此类属性的名称,但您可以使用IndexerNameAttribute
它来强制它以不同的方式命名属性。它还将DefaultMemberAttribute
使用该属性的索引器粘贴在类上,因此它被视为 VB 中的默认属性(以及其他显示索引属性的 CLS 兼容语言)。
在使用其他语言编写的类时,C# 会查找DefaultMemberAttribute
. 如果它存在,则它引用的索引属性显示为 C# 中该类的索引器。非默认的索引属性只能通过直接调用其访问器方法 (get_Foo
和set_Foo
) 从 C# 访问 - 尽管这将在 C# 4 中针对 COM 导入的接口进行更改。
索引器是第二层语法糖。使用属性,get 和 set 被转换为方法调用,这些方法以get_
/为前缀set_
。在索引器的情况下,索引器转换为方法 Item()。任何索引器参数都是方法的第一个参数。此外,get_
/set_
是方法的前缀。
对于那些喜欢示例的人:
string foo;
public string Foo {
get {
return foo;
}
set {
foo = value;
}
}
// becomes
string foo;
public string get_Foo() {
return foo;
}
public void set_Foo(string value) {
foo = value;
}
在这里,索引器会发生什么:
string[] backingFoo;
public string this[int index] {
get {
return backingFoo[index];
}
set {
backingFoo[index] = value;
}
}
// becomes
string[] backingFoo;
public string get_Foo(int index) {
return backingFoo[index];
}
public void set_Foo(int index, string value) {
backingFoo[index] = value;
}