zoukankan      html  css  js  c++  java
  • 常量、字段、方法、属性和索引器(C#)

    常量(Constants)

    常量是在编译时已知并在程序的生存期内不发生更改的不可变值。 常量使用 const 修饰符进行声明。 只有 C# 内置类型(System.Object 除外)可以声明为 const。用户定义的类型(包括类、结构和数组)不能为 const。 请使用 readonly 修饰符创建在运行时初始化一次即不可再更改的类、结构或数组。
    注:内置类型表如下

    这里写图片描述

    常量必须在声明时初始化。例如:
    C#:

    class Calendar1
    {
        public const int months = 12;
    }

    在此示例中,常量 months 始终为 12,不可更改,即使是该类自身也不能更改它。 实际上,当编译器遇到 C# 源代码(例如 months)中的常量修饰符时,将直接把文本值替换到它生成的中间语言 (IL) 代码中。 因为在运行时没有与常量关联的变量地址,所以 const 字段不能通过引用传递,并且不能在表达式中作为左值出现。

    字段(fields )

    “字段”是直接在类或结构中声明的任何类型的变量。 字段是其包含类型的“成员”。

    类或结构可以拥有实例字段(instance fields)静态字段( static fields ),或同时拥有两者。 实例字段特定于类型的实例。 如果您拥有类 T 和实例字段 F,可以创建类型 T 的两个对象,并修改每个对象中 F 的值,这不影响另一对象中的该值。 相比之下,静态字段属于类本身,在该类的所有实例中共享。 从实例 A 所做的更改将立刻呈现在实例 B 和 C 上(如果它们访问该字段)。

    通常应仅为具有私有或受保护可访问性的变量使用字段。 您的类向客户端代码公开的数据应通过方法、属性和索引器提供。 通过使用这些构造间接访问内部字段,可以针对无效的输入值提供防护。 存储由公共属性公开的数据的私有字段称为“后备存储”或“支持字段”。

    • 在类块中通过指定字段的访问级别,然后指定字段的类型,再指定字段的名称来声明这些字段。 例如:
      C#:
    public class CalendarEntry
    {
        // private field
        private DateTime date;
    
        // public field (Generally not recommended.)
        public string day;
        ...
    }
    • 若要访问对象中的字段,请在对象名称后面添加一个句点,然后添加该字段的名称,比如 objectname.fieldname。 例如:
      C#:
    CalendarEntry birthday = new CalendarEntry();
    birthday.day = "Saturday";
    • 声明字段时可以使用赋值运算符为字段指定一个初始值。 例如,若要自动将 “Monday” 赋给 day 字段,需要声明 day,如下例所示:
      C#:
    public class CalendarDateWithInitialization
    {
        public string day = "Monday";
        //...
    }
    • 字段可标记为 public、private、protected、internal 或 protected internal。 这些访问修饰符定义类的使用者访问字段的方式。
      注:访问修饰符

    这里写图片描述

    • 可以选择将字段声明为 static。 这使得调用方在任何时候都能使用字段,即使类没有任何实例。

    • 可以将字段声明为 readonly。 只读字段只能在初始化期间或在构造函数中赋值。 static readonly 字段非常类似于常数,只不过 C# 编译器不能在编译时访问静态只读字段的值,而只能在运行时访问。

    注:变量与字段的区别与联系

    public class Test
    {
        // field在这里是一个字段变量
        public int field =0;
        // 静态字段,
        public static int filed2 =1;
    
        public void TestMethod()
        {
            // 此时a是一个变量,并且是一个局部变量,a就不是字段了
            // 而对于field 和field2我们最好认为其是一个字段,但是它也是变量,我们一般叫法为 “字段变量”
            int a =2;
            Console.Write(a);
        }
    }

    方法(method)

    方法是包含一系列语句的代码块。 程序通过调用该方法并指定任何所需的方法参数使语句得以执行。 在 C# 中,每个执行的指令均在方法的上下文中执行。 Main 方法是每个 C# 应用程序的入口点,并在启动程序时由公共语言运行时 (CLR) 调用。

    方法签名

    • 通过指定访问级别(如 public 或 private)、可选修饰符(如 abstract 或 sealed)、返回值、方法的名称以及任何方法参数,在类或结构中声明方法。 这些部件一起构成方法的签名。
    • 方法参数在括号内,并且用逗号分隔。 空括号指示方法不需要任何参数。

    注:出于方法重载的目的,方法的返回类型不是方法签名的一部分。 但是在确定委托和它所指向的方法之间的兼容性时,它是方法签名的一部分。


    补充:方法重载是指在一个类中定义多个同名的方法,但要求每个方法具有不同的参数的类型或参数的个数。比如:

       public void Func(){}
       public void Func(int a){}
       public void Func(int a,int b){}
       ···
       Func(a);//会调用public void Func(int a)这个版本

    具体规范:

    • 方法名一定要相同。
    • 方法的参数表必须不同,包括参数的类型或个数,以此区分不同的方法体。(如果参数个数不同,就不管它的参数类型了。如果参数个数相同,那么参数的类型或者参数的顺序必须不同。)
    • 方法的返回类型、修饰符可以相同,也可不同。即在C#中不能只根据返回值的类型不同来区分不同的重载函数。

    方法访问

    调用对象上的方法就像访问字段。 在对象名之后添加一个句点、方法名和括号。 参数列在括号里,并且用逗号分隔。

    方法参数与参数

    该方法定义指定任何所需参数的名称和类型。调用代码调用该方法时,它为每个参数提供了称为参数的具体值。 参数必须与参数类型兼容,但调用代码中使用的参数名(如果有)不需要与方法中定义的参数名相同。

    按引用传递与按值传递

    默认情况下,值类型传递给方法时,传递的是副本而不是对象本身。 因此,对参数的更改不会影响调用方法中的原始副本。可以使用 ref 关键字按引用传递值类型。

    引用类型的对象传递到方法中时,将传递对对象的引用。 也就是说,该方法接收的不是对象本身,而是指示该对象位置的参数。 如果通过使用此引用更改对象的成员,即使是按值传递该对象,此更改也会反映在调用方法的参数中。

    通过使用 class 关键字创建引用类型,如以下示例所示。

    public class SampleRefType
    {
        public int value;
    }

    现在,如果将基于此类型的对象传递到方法,则将传递对对象的引用。 下面的示例将 SampleRefType 类型的对象传递到 ModifyObject 方法。

    public static void TestRefType()
    {
        SampleRefType rt = new SampleRefType();
        rt.value = 44;
        ModifyObject(rt);
        Console.WriteLine(rt.value);
    }
    static void ModifyObject(SampleRefType obj)
    {
        obj.value = 33;
    }
    

    该示例执行的内容实质上与先前示例相同,均按值将参数传递到方法。 但是因为使用了引用类型,结果有所不同。 ModifyObject 中所做的对形参 obj 的 value 字段的修改,也会更改 TestRefType 方法中实参 rt 的 value 字段。 TestRefType 方法显示 33 作为输出。

    返回值

    方法可以将值返回到调用方。如果列在方法名之前的返回类型不是 void,则该方法可通过使用 return 关键字返回值。带 return 关键字,后跟与返回类型匹配的值的语句将该值返回到方法调用方。return 关键字还会停止执行该方法。如果返回类型为 void,没有值的 return 语句仍可用于停止执行该方法。 没有 return 关键字,当方法到达代码块结尾时,将停止执行。具有非空的返回类型的方法都需要使用 return 关键字来返回值。例如,这两种方法都使用 return 关键字来返回整数:

    class SimpleMath
    {
        public int AddTwoNumbers(int number1, int number2)
        {
            return number1 + number2;
        }
    
        public int SquareANumber(int number)
        {
            return number * number;
        }
    }

    若要使用从方法返回的值,调用方法可以在相同类型的值足够的地方使用该方法调用本身。 也可以将返回值分配给变量。 例如,以下两个代码示例实现了相同的目标:

    int result = obj.AddTwoNumbers(1, 2);
    result = obj.SquareANumber(result);
    // The result is 9.
    Console.WriteLine(result);
    result = obj.SquareANumber(obj.AddTwoNumbers(1, 2));
    // The result is 9.
    Console.WriteLine(result);

    属性(property)

    属性是一种成员,它提供灵活的机制来读取、写入或计算私有字段的值。 属性可用作公共数据成员,但它们实际上是称为“访问器”的特殊方法。 这使得可以轻松访问数据,还有助于提高方法的安全性和灵活性。

    属性结合了字段和方法的多个方面。 对于对象的用户,属性显示为字段,访问该属性需要相同的语法。 对于类的实现者,属性是一个或两个代码块,表示一个 get 访问器和/或一个 set 访问器。 当读取属性时,执行 get 访问器的代码块;当向属性分配一个新值时,执行 set 访问器的代码块。 不具有 set 访问器的属性被视为只读属性。 不具有 get 访问器的属性被视为只写属性。 同时具有这两个访问器的属性是读写属性。

    与字段不同,属性不作为变量来分类。 因此,不能将属性作为 ref(C# 参考)参数或 out(C# 参考)参数传递。

    属性具有多种用法:它们可在允许更改前验证数据;它们可透明地公开某个类上的数据,该类的数据实际上是从其他源(例如数据库)检索到的;当数据被更改时,它们可采取行动,例如引发事件或更改其他字段的值。

    属性在类块中是按以下方式来声明的:指定字段的访问级别,接下来指定属性的类型和名称,然后跟上声明 get 访问器和/或 set 访问器的代码块。 例如:

    public class Date
    {
        private int month = 7;  // Backing store
    
        public int Month
        {
            get
            {
                return month;
            }
            set
            {
                if ((value > 0) && (value < 13))
                {
                    month = value;
                }
            }
        }
    }

    在此示例中,Month 是作为属性声明的,这样 set 访问器可确保 Month 值设置为 1 和 12 之间。 Month 属性使用私有字段来跟踪该实际值。 属性的数据的真实位置经常称为属性的“后备存储”。属性使用作为后备存储的私有字段是很常见的。 将字段标记为私有可确保该字段只能通过调用属性来更改。

    get 访问器

    get 访问器体与方法体相似。 它必须返回属性类型的值。 执行 get 访问器相当于读取字段的值。

    以下是返回私有字段 name 的值的 get 访问器:

    class Person
    {
        private string name;  // the name field
        public string Name    // the Name property
        {
            get
            {
                return name;
            }
        }
    }

    当引用属性时,除非该属性为赋值目标,否则将调用 get 访问器以读取该属性的值。 例如:

    Person person = new Person();
    //...
    
    System.Console.Write(person.Name);  // the get accessor is invoked here
    

    get 访问器必须以 return 或 throw 语句终止,并且控制权不能离开访问器体。

    通过使用 get 访问器更改对象的状态不是一种好的编程风格。 例如,以下访问器在每次访问 number 字段时都会产生更改对象状态的副作用。

    private int number;
    public int Number
    {
        get
        {
            return number++;   // Don't do this
        }
    }

    get 访问器可用于返回字段值,或用于计算并返回字段值。 例如:

    class Employee
    {
        private string name;
        public string Name
        {
            get
            {
                return name != null ? name : "NA";
            }
        }
    }

    在上一个代码段中,如果不对 Name 属性赋值,它将返回值 NA。

    set 访问器

    set 访问器类似于返回类型为 void 的方法。 它使用称为 value 的隐式参数,此参数的类型是属性的类型。 在下面的示例中,将 set 访问器添加到 Name 属性:

    class Person
    {
        private string name;  // the name field
        public string Name    // the Name property
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
            }
        }
    }

    当对属性赋值时,用提供新值的参数调用 set 访问器。 例如:

    Person person = new Person();
    person.Name = "Joe";  // the set accessor is invoked here                
    
    System.Console.Write(person.Name);  // the get accessor is invoked here

    在 set 访问器中,对局部变量声明使用隐式参数名称 value 是错误的。

    备注

    • 可将属性标记为 public、private、protected、internal 或 protected internal。 这些访问修饰符定义类的用户如何才能访问属性。 同一属性的 get 和 set 访问器可能具有不同的访问修饰符。 例如,get 可能是 public 以允许来自类型外的只读访问;set 可能是 private 或 protected。 有关更多信息,请参见 访问修饰符(C# 编程指南)
    • 可以使用 static 关键字将属性声明为静态属性。 这使得调用方随时可使用该属性,即使不存在类的实例。 有关更多信息,请参见 静态类和静态类成员(C# 编程指南)
    • 可以使用 virtual 关键字将属性标记为虚属性。 这样,派生类就可以通过使用 override 关键字来重写事件行为。 有关这些选项的更多信息,请参见 继承(C# 编程指南)
    • 重写虚属性的属性还可以是 sealed 的,这表示它对派生类不再是虚拟的。 最后,可以将属性声明为 abstract。 这意味着类中没有任何实现,派生类必须编写自己的实现。 有关这些选项的更多信息,请参见 抽象类、密封类及类成员(C# 编程指南)
    • 对 static 属性的访问器使用 virtual、abstract或 override修饰符是错误的。

    索引器(Indexers)

    • 索引器允许类或结构的实例就像数组一样进行索引。 索引器类似于属性,不同之处在于它们的取值函数采用参数。
    • 使用索引器可以用类似于数组的方式为对象建立索引。
    • get 取值函数返回值。 set 取值函数分配值。
    • this 关键字用于定义索引器。
    • value 关键字用于定义由 set 索引器分配的值。
    • 索引器不必根据整数值进行索引;由你决定如何定义 特定的查找机制。
    • 索引器可被重载。
    • 索引器可以有多个形参,例如当访问二维数组时。

    在下面的示例中,定义了一个泛型类,并为其提供了简单的 get 和 set 取值函数方法(作为分配和检索值的方法)。 Program 类创建了此类的一个实例,用于存储字符串。

    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]);
        }
    }
    // Output:
    // Hello, World.
    

    参考资料

    1. 常量(C# 编程指南):https://msdn.microsoft.com/zh-cn/library/ms173119.aspx
    2. 字段(C# 编程指南):https://msdn.microsoft.com/zh-cn/library/ms173118.aspx
    3. 方法(C# 编程指南):https://msdn.microsoft.com/zh-cn/library/ms173114.aspx
    4. 使用属性(C# 编程指南):https://msdn.microsoft.com/zh-cn/library/w86s7x04.aspx
    5. 索引器(C# 编程指南):https://msdn.microsoft.com/zh-cn/library/6x16t2tx.aspx#bkmk_relatedsections

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    使用Pandas DataFrames在Python中绘制条形图
    在Pandas DataFrames中选择行和列使用iloc,loc和ix
    如何使用[] 、. loc,iloc,.at和.iat
    Pandas 分类数据
    按索引和值对Pandas DataFrame进行排序
    可能需要的建议
    时间线
    第四章-赶路
    第三章-担忧
    lipo命令拆分、合并iOS静态库
  • 原文地址:https://www.cnblogs.com/gongchuangsu/p/4850196.html
Copyright © 2011-2022 走看看