无参属性大家可以参考比对下。
今天又翻了翻书,看看有参属性(索引器)跟无参属性有啥区别。
属性的get访问器方法不接受参数,所以我们将这些属性称为无参属性,因为无参属性与字段的访问有些相似,所以这些属性很容易理解。
除了这些与字段访问有些相似的属性,C#还支持有参属性(索引器),它的get访问器方法接受一个或多个参数,set访问器方法接受两个或多个参数。
C#使用数组风格的语法来公开有参属性,可以把索引器看作C#重载[]操作符的一种方式。
class test
{
private int[] nums;
private int length;
public string sss
{
get;
set;
}
public test(int len)
{
if (len <= 0)
{
Console.WriteLine("输入大于0的整数");
throw new ArgumentOutOfRangeException("输入大于0的整数!");
}
length = len;
nums = new int[length];
}
//[IndexerName("Nums")]
public int this[int post]
{
get { if (post < 0 || post >= length) { Console.WriteLine("搞毛呢。。"); throw new ArgumentOutOfRangeException("post"); } else { return nums[post]; } }
set { if (post >= 0 && post < length&&nums!=null) { nums[post] = value; } else { throw new ArgumentOutOfRangeException("post", post.ToString()); } }
}
public string this[int i, string s]
{
get { return ""; }
set { }
}
}
class Program
{
static void Main()
{
PropertyInfo[] propertys = typeof(test).GetProperties();
foreach (PropertyInfo p in propertys)
{
Console.WriteLine("GetMethod的名称:{0},SetMethod的名称:{1}", p.GetGetMethod().Name, p.GetSetMethod().Name);
}
test t = new test(15);
for (int i = 0; i < 15; i++)
{
t[i] = i + 1;
Console.WriteLine(t[i]);
}
Console.ReadKey();
}
}
所有索引器至少要有一个参数,可以有更多,这些参数和返回类型可以是除了void以外的任意类型。在System.Drawing.Imaging.ColorMatrix类中,提供了一个有多个参数的一个索引器的例子 ,大家可以去参考下 :
public float this[int row, int column]
{
get
{
return this.GetMatrix()[row][column];
}
set
{
float[][] numArray;
numArray = this.GetMatrix();
numArray[row][column] = value;
this.SetMatrix(numArray);
return;
}
}
经常要创建索引器来查询关联数组中的值,System.Collections.Generic.Dictionary类就提供了这样的一个索引器,它获取一个值,并返回与该键关联的值。
public TValue this[TKey key]
{
get
{
int num;
TValue local;
num = this.FindEntry(key);
if (num < 0)
{
goto Label_001E;
}
return &(this.entries[num]).value;
Label_001E:
ThrowHelper.ThrowKeyNotFoundException();
return default(TValue);
}
set
{
this.Insert(key, value, 0);
return;
}
}
和无参属性不同,类型可以提供多个重载的索引器,只要这些索引器的签名不同。
CLR本身并不区分无参属性和有参属性,对于CLR来说属性就是类型中定义的一些方法和一些元数据。C#只允许在对象的实例上定义索引器,C#没有提供定义静态索引器属性的语法,但是CLR是支持静态有参属性的。
由于C#的索引器语法不允许开放人员指定索引器名称,所以编译器就为索引器选择了一个默认的名称,如果你注意过你应该发现了吧:Item,编译器生成的方法名就是get_Item,set_Item。从第一段代码就能发现了
使用C#永远不会看到Item这个名称,所以一般不需要关心编译器选定的这个名称,但是如果为一个类型设计的索引器要是有其他语言的代码访问,就可能需要更改索引器的默认Item名称了。C#允许向索引器应用System.Runtime.ComplierServices.IndexerNameAttribute定制attribute来重命名这些方法。
[IndexerName("Nums")]
public int this[int post]
{
get { if (post < 0 || post >= length) { Console.WriteLine("搞毛呢。。"); throw new ArgumentOutOfRangeException("post"); } else { return nums[post]; } }
set { if (post >= 0 && post < length&&nums!=null) { nums[post] = value; } else { throw new ArgumentOutOfRangeException("post", post.ToString()); } }
}
public string this[int i, string s]//如果这里不使用IndexerName修改默认的Item为Nums就会报错:“两个索引器的名称不同;在类型中的每个索引器上的IndexerName特性都必须使用相同的名称。”因为一个类型中可以定义多个索引器,只要索引器的参数集不同就行了,其他语言中IndexerName属性允许定义多个具有相同签名的索引器,每个索引器有不同的名称,但是在C#中这是不允许的,因为它的语法不是通过名称来引用索引器。
{
get { return ""; }
set { }
}
这里编译器就会生成名为get_Nums,set_Nums的方法,而不是默认的了。使用IndexerName 如果代码中包含多个名称不同的有参属性,C#无法编译代码。
C#将索引器堪称是对[]操作符的一种重载方式,而且[]操作符不能用来消除具有不同方法名和相同参数集的有参属性的歧义。
关于有参属性和无参属性如果有没指出来的地方,欢迎提出,大家共同进步…^_^