1.无参属性
CLR支持静态属性,实例属性,抽象属性,虚拟属性,但不能被重载。
属性在MSIL中生成以下内容:
get_XX方法,当在属性中定义了get的时候——XX为属性名
set_XX方法,当在属性中定义了set的时候——XX为属性名
一个位于原数据中的属性定义。
属性不能作为out/ref传递给方法,字段则可以。
如果属性中执行语句过多,要花很多时间,这时候优先选用方法。例如线程同步和Remoting。
多次访问属性,每次返回的值可能不同;而字段的值每次返回都不会改变。例如System.DateTime属性——MS以后会将其改为方法。
2.有参属性
定义,有参属性的get方法可以接受1个或者更多参数,set方法可以接受2个或者更多参数
——对比,无参属性get方法无参数,set方法有1个参数。
C#索引器语法,是对[ ]这个运算符的重载,示例如下:
public class FailSoftArray
{
int[] a;
public int length;
public FailSoftArray(int length)
{
a = new int[length];
this.length = length;
}
public int this[int index]
{
get
{
if (index >= 0 & index < length)
{
return a[index];
}
else
throw new ArgumentOutOfRangeException();
}
set
{
if (index >= 0 & index < length)
{
a[index] = value;
}
else
throw new ArgumentOutOfRangeException();
}
}
}
public class TestIndex
{
public TestIndex()
{
FailSoftArray fs = new FailSoftArray(5);
for (int i = 0; i < 5; i++)
{
fs[i] = i * 10;
}
}
}
{
int[] a;
public int length;
public FailSoftArray(int length)
{
a = new int[length];
this.length = length;
}
public int this[int index]
{
get
{
if (index >= 0 & index < length)
{
return a[index];
}
else
throw new ArgumentOutOfRangeException();
}
set
{
if (index >= 0 & index < length)
{
a[index] = value;
}
else
throw new ArgumentOutOfRangeException();
}
}
}
public class TestIndex
{
public TestIndex()
{
FailSoftArray fs = new FailSoftArray(5);
for (int i = 0; i < 5; i++)
{
fs[i] = i * 10;
}
}
}
索引器是可以重载的,不能在this[]的类型上重载,只能在参数上重载——无参属性不可以重载:
public int this[int index]
{
set { }
}
public int this[double index]
{
set { }
}
{
set { }
}
public int this[double index]
{
set { }
}
以下索引器重载是不对的,尽管改变了Item,在MSIL中是有不同方法名的两套方法,却具有相同的参数集;但是C#不是按名称引用索引器,而是按参数集。
[IndexerName("Jeff")]
public String this[bool b]
{
set { }
}
[IndexerName("Jax.Bao")]
public Int32 this[bool b]
{
set { }
}
public String this[bool b]
{
set { }
}
[IndexerName("Jax.Bao")]
public Int32 this[bool b]
{
set { }
}
CLR不区分无参属性和有参属性,都是生成一对方法和一块元数据:
get_Item方法,当在属性中定义了get的时候
set_Item方法,当在属性中定义了set的时候
一个位于原数据中的属性定义。在MSIL中,有专门用于有参属性的元数据定义表。
对于索引器,使用get_Item和set_Item这两个默认名称。同时,通过反射查看类型是否有Item属性,来判断该类型是否提供了索引器(Generic.List)。
但是,C#编程中不会看到Item这一默认属性,在与其它语言交互时,可能需要把Item改为其他的名称,方法如下:
using System.Runtime.CompilerServices;
public sealed class BitArray
{
[IndexerName("Bit")]
public bool this[int bitPos]
{
set { }
}
}
于是,MSIL生成get_Bit和set_Bit方法。NET中的String.String类型就是Chars而不是Item。public sealed class BitArray
{
[IndexerName("Bit")]
public bool this[int bitPos]
{
set { }
}
}
索引器语法this[..],是C#团队选择的表示方式,意味着C#只允许在对象的实例上定义索引器。
CLR支持静态有参属性,但是C#没有提供相关语法
补充:VB.NET"默认属性"语法
将C#的索引器示例改造成VB.NET的:将属性声明为Default,并加上参数,只是这里的this不再是关键字,而是一个自定义的属性
Public Class FailSoftArray
Public length As Integer
Private a(length) As Integer
Public Sub New(ByVal length As Integer)
Me.length = length
End Sub
Default Public Property this(ByVal index As Integer)
Get
If (index >= 0 & index < length) Then
Return a(index)
Else
Throw New ArgumentOutOfRangeException()
End If
End Get
Set(ByVal value)
If (index >= 0 & index < length) Then
a(index) = value
Else
Throw New ArgumentOutOfRangeException()
End If
End Set
End Property
End Class
Public Class TestIndex
Public Sub New()
Dim fs As FailSoftArray = New FailSoftArray(5)
Dim i As Integer
For i = 1 To 5
fs(i) = i * 10
Next
End Sub
End Class
Public length As Integer
Private a(length) As Integer
Public Sub New(ByVal length As Integer)
Me.length = length
End Sub
Default Public Property this(ByVal index As Integer)
Get
If (index >= 0 & index < length) Then
Return a(index)
Else
Throw New ArgumentOutOfRangeException()
End If
End Get
Set(ByVal value)
If (index >= 0 & index < length) Then
a(index) = value
Else
Throw New ArgumentOutOfRangeException()
End If
End Set
End Property
End Class
Public Class TestIndex
Public Sub New()
Dim fs As FailSoftArray = New FailSoftArray(5)
Dim i As Integer
For i = 1 To 5
fs(i) = i * 10
Next
End Sub
End Class
3.性能
内联:就是方法下包括全部代码,不需要将部分代码放到额外的调用函数中——消除了运行时与调用相关的开销,代价是编译后方法的代码很庞大。
内联属性方法,因为其通常包括极少代码,所以编译后代码量更小,执行更快。
由于JIT调试时期不会内联属性方法,所以属性访问器在Release版本性能要快于Debug版本——字段在两个版本中执行得同样快。
4.属性访问器的可访问性
可以get是public的;而set是protected的
get/set的可访问性是在属性名前声明的
public String Name //这里的public决定了get/set默认的可访问性
{
get { return null; }
protected set { } //这里提升了set的可访问性
}
{
get { return null; }
protected set { } //这里提升了set的可访问性
}
5.虽然属性实际上就是方法,但是不允许泛型属性。