C#学习笔记 -- 对象初始化语句、索引器、访问器的修饰符

1、对象初始化语句

扩展语法

  • 有如下两种扩展语法,

    • 第一种当类中没有声明构造器或者声明了无参构造器才能用

    • 第二种当类中声明了有参构造器才能用

new ExampleClass {FieldOrProp = InitProp, FieldOrProp = InitProp, ...};
new ExampleClass(ArgList) {FieldOrProp = InitProp, FieldOrProp = InitProp, ...};

对于一个名为Point、有两个公有整型字段X、Y的类, 可以使用扩展语法如下表示

new Point {X = 5, Y = 6};
注意
  1. 创建对象的代码必须能够访问要初始化的字段和属性, 例如上例中X、Y是公有的

  2. 初始化发生在构造方法执行之后, 因此构造方法中设置的值可能会在之后对象初始化中重置为相同或不同的值

  3. 接第二条, 即使用有参构造器也会重置为扩展语法中的值

例子

class Program713
{
    public int X = 1;
    public int Y = 2;
​
    public Program713(int x, int y)
    {
        X = x;
        Y = y;
    }
​
    public Program713()
    {
    }
}
static void Main(sting[] args)
{
    Program713 program713Cons = new Program713();
    Program713 program713Args = new Program713(3, 4) { X = 5, Y = 6 };
    Program713 program713 = new Program713 { X = 7, Y = 8 };
    Console.WriteLine($"构造函数构造出的实例: X = {program713Cons.X}, Y = {program713Cons.Y}"); //1 2
    Console.WriteLine($"有参对象初始化语句初始的类: X = {program713Args.X}, Y = {program713Args.Y}"); //5 6
    Console.WriteLine($"无参对象初始化语句初始的类: X = {program713.X}, Y = {program713.Y}"); //7 8
}

2、索引器

(1)什么是索引器

索引器是一组get和set访问器, 与属性类似

string this [int index]
{
    set {}
    get {}
}

(2)索引器和属性

  • 和属性一样, 索引器不用分配内存来存储

  • 索引器和属性都主要被用来访问器他数据成员, 他们与这些成员关联, 并为他们提供获取和设置访问

    • 属性通常表示单个数据成员

    • 索引器通常表示多个数据成员

  • 可以认为索引器是为类的多个数据成员提供get的set访问的属性

  • 通过提供索引器, 可以在许多可能的数据成员中进行选择

  • 索引本身可以是任何类型, 而不仅仅是数值类型

注意
  1. 与属性一样, 索引器可以只有一个访问器, 也可以两个都有

  2. 索引器总是实例成员, 因此不能被声明为静态

  3. 与属性一样, 实现get和set访问器的代码不一定要关联到某个字段或者属性, 这段代码可以做任何事情也可以什么都不做, 只要get访问器返回某个指定的类型即可

(3)声明索引器

  • 索引器没有名称, 在名称位置是关键字this

  • 参数列表在方括号中间

  • 参数列表必须至少声明一个参数

ReturnType this [Type arg, ...]
{
    set {}
    get {}
}

(4)索引器的set访问器

当索引器被用于赋值时, set访问器被调用, 并接受两项数据

  • 一个名为value的隐式参数, 其中持有要保存的数据

  • 一个或更多索引参数, 表示数据应该保存到哪里

emp[索引参数] = 值;

在访问器中的代码必须检查索引参数, 以确定数据应该存往何处, 然后保存他

Type this [Args]
{
    set{}
    get{}
}
void set(Args, Type value)
{
    ...
}

上方的代码块表示set访问器的语义

  • 它的返回类型为void

  • 他使用的参数列表和索引器声明中相同

  • 有一个value隐式参数, 类型和索引器类型相同

(5)索引器的get访问器

当使用索引器获取值时, 可以通过一个或多个索引参数调用get访问器, 索引参数指示获取那个值

string s = emp[索引参数]
Type this [Args]
{
    set{}
    get{}
}
Type get (Args)
{
    return vars;
}

上方的代码块表示get访问器的语义

  • 他使用的参数列表和索引器声明中相同

  • 返回值类型和索引器类型相同

(6)索引器隐式调用、自动调用

  • 索引器不能显示调用setter和getter

  • 取而代之, 当索引器在表达式中取值的时候, 将自动调用get访问器.

  • 当使用赋值语句对索引器赋值时, 自动调用set访问器

  • 在调用索引器时, 要在方括号内提供参数

(7)索引器例子

例子一: 为Emplyee声明索引器
  • 索引器需要读写string类型的值, 所以string必须声明为索引器的类型, 他必须声明为public, 以便从类的外部访问

  • 3个字段被随意的索引为整数0~2, 所以本例中index形参必须为int

  • 在setter中, 代码确定索引指的是那个字段, 并把隐式变量value的值赋值给他

  • 在getter中, 代码确定索引的是哪个字段, 并返回该字段的值

class Employee
{
    public string LastName;
    public string FirstName;
    public string CityOfBirth;
​
    public string this [int index]
    {
        set 
        {
            switch (index)
            {
                case 0: LastName = value;
                    break;
​
                case 1:
                    FirstName = value;
                    break;
​
                case 2:
                    CityOfBirth = value;
                    break;
                default:
                    throw new ArgumentOutOfRangeException("index");
            }
        }
        get 
        {
            switch (index)
            {
                case 0:
                    return LastName;
                case 1:
                    return FirstName;
                case 2:
                    return CityOfBirth;
                default:
                    throw new ArgumentOutOfRangeException("index");
            }
        }
    }
}
例子二
class Class1
{
    int Temp0;
    int Temp1;
    public int this[int index]
    {
        set 
        {
            if (index == 0)
            {
                Temp0 = value;
            }
            else if (index ==1)
            {
                Temp1 = value;
            }
            else
            {
                throw new ArgumentOutOfRangeException("index");
            }
        }
​
        get 
        {
            if (index > 1 || index < 0)
            {
                throw new ArgumentOutOfRangeException("index");
            }
            return index == 0 ? Temp0 : Temp1;
        }
    }
}
static void Main(string[] args)
{
    Class1 class1 = new Class1();
    Console.WriteLine($"调用索引setter前 调用索引getter Value = {class1[0]}, {class1[1]}");
    class1[0] = 10;
    class1[1] = 25;
    Console.WriteLine($"调用索引setter后 调用索引getter Value = {class1[0]}, {class1[1]}");
}

(9)索引器重载

  • 只要索引器的参数列表不同, 类可以拥有任意多个索引器, 构成索引器重载

  • 索引器类型不同是不够的, 因为所有索引器都有相同的名称this, 返回值类型不同不构成重载

class Progrom717_9
{
    public string this[int index]
    {
        set { }
        get { }
    }
​
    public string this[int index1, int index2]
    {
        set { }
        get { }
    }
​
    public int this[float index]
    {
        set { }
        get { }
    }
}

3、访问器的修饰符

  • 默认情况下, 成员的两个访问器的访问级别和成员自身相同

    • 即如果一个属性的访问级别是public, 那么它的访问器也是public

  • 可以将两个访问器分配不同访问级别, 如下方例子

  • 尽管可以从类的外部读取属性, 但是只能在类的内部设置他, 下方例子在构造函数中设置

class Person
{
    //属性:名字, setter访问器是私有的, 在构造函数中设置属性
    public string Name { private set; get; }
​
    public Person(string name)
    {
        Name = name;
    }
}
static void Main(string[] args)
{
    Person person = new Person("Lyu King");
    Console.WriteLine($"这个人的名字叫: {person.Name}");
}
注意

访问器的访问修饰符有如下几个限制

  • 仅当成员(属性或索引器)既有getter也有setter时, 其访问器才能有访问修饰符

  • 虽然两个访问器都必须出现, 但他们中只能有一个访问修饰符

  • 访问器的访问修饰符限制必须比成员的访问级别更严格

    • 比如一个属性访问级别是public, 那么任何一个访问器的级别必须是如下图(访问器级别显示层次) public之下的层级

posted on 2023-05-21 12:40  老菜农  阅读(49)  评论(0编辑  收藏  举报

导航