概述:类及类成员。
零 类及类成员简介
0.类
- 类:创建对象的模板。
- C#中的一切皆是类与类的实例(对象)。
1.类的访修饰符
- 一般类:
public
:公开的,公共的。internal
:程序集内部的。
- 嵌套类:嵌套类是类的成员,所以可以使用类成员的访问修饰符。
2.类的成员
- 数据成员
- 字段
- 常量
- 事件
- 函数成员
- 方法
- 属性
- 构造函数
- 终接器
- 运算符
- 索引器
- 嵌套类型
一 类成员的访问修饰符
0.类成员的访问修饰符:
public
:公开的,无限制,全部的类都可以访问。protected
:派生类中可访问。internal
:同一个程序集内的其他的类可访问。private
:只能在本类的内部访问。protected internal
:在派生类或者同一个程序集内的类可访问。-
private internal
:在派生类且是同一个程序集内的类才可以访问。 - 在类的内部类的成员都是可以访问的
二 字段
- 默认是实例的,使用
static
修饰符变成静态的。 - 一般把字段设置为
private
,然后调用方法来更改字段。(数据封装)
三 常量
0.readonly与cont区别
- const
- 只能在声明时候赋值。
- 只能赋值编译时候能确定的值,一般是字面量。
- 在程序编译过程中,会把常量转换为字面量,如此一来如果更改了字面量然后在编译,那么之前编译的版本值不会变。
- 常量默认是static的,但是不能显式加上static。
- readonly
- 可以在声明时候赋值,也可以在构造函数中赋值。
- 可以赋值变量。
- 可以是实例的,也可以是静态的。
四 方法
- 默认是实例的,使用
static
修饰符变成静态的。 - C#中除非特别指定,否则所有的参数都是传值。
- ref参数(引用参数):要求对传递给方法的参数进行初始化。
- out参数(输出参数):传递变量给方法时候可以不进行初始化,但是在方法中必须对变量进行赋值。
- 参数数组:有时候希望参数的数量是可变的。
- 参数数组必须是方法声明中的最后一个参数。
- 调用者可以为参数数组指定零个参数,这会造成包含零个数据项的一个数组。
- 命名参数:传递参数给方法时参数需要按照一定的顺序;但是命名参数运行按任意顺序传递。
- 可选参数:可选参数必须是方法定义的最后一个参数,必须给可选参数定义默认值。
/// <summary>
/// 引用参数
/// </summary>
/// <param name="refParam"></param>
public static void RefParamMethod(ref int refParam)
//refParam参数,传入必须初始化
=>refParam = 2;
/// <summary>
/// 输出参数
/// </summary>
/// <param name="outParam"></param>
public static void OutParamMethod(out int outParam)
//outParam参数,在传入前可以不用初始化,但是必须在方法中赋值
=>outParam = 2;
/// <summary>
/// 用于测试方法 命名参数调用
/// </summary>
/// <param name="oneParam"></param>
/// <param name="twoParam"></param>
public static void NameParamMethod(int oneParam, int twoParam)
=> Console.WriteLine("NameParamMethod函数。");
/// <summary>
/// 参数数组
/// 1.参数数组不一定是方法声明中的唯一采参数。但是,参数数组必须是方法声明中的**最后一个参数**。
/// 由于只有最后一个参数才能是参数数组,所以方法最多只能有一个参数数组。
/// 2.调用者可以为参数数组指定零个参数,这会造成包含零个数据项的一个数组。
/// 3.参数数组是类型安全的--传入参数类型必须匹配与数组指定的类型。
/// 4.调用者可以显示地使用一个数组,而不是以逗号分割的参数列表。最终生成的CLI代码是一样的。
/// 5.假如目标方法的实现要求一个最起码的参数数量,请在方法声明中显示指定必须提供的参数。
/// </summary>
/// <param name="outParam"></param>
public static void ParamArrayMethod(params int[] paramArray)
{
Console.Write("传入的参数:");
foreach (var param in paramArray)
{
Console.Write($" {param} ");
}
Console.WriteLine();
}
/// <summary>
/// 可选参数
/// </summary>
/// <param name="oneParam"></param>
/// <param name="optionalParam"></param>
public static void OptionalParamMethod(int oneParam, int optionalParam = default(int))
=> Console.WriteLine($"传入的参数:{oneParam} {optionalParam}");
static void Main(string[] args)
{
/*引用参数 ref*/
int a = 1;
//输出:ref,调用方法前,a=1。
Console.WriteLine($"ref,调用方法前,a={a}。");
RefParamMethod(ref a);
//输出:ref,调用方法后,a=2。
Console.WriteLine($"ref,调用方法后,a={a}。");
Console.WriteLine($"------------------------------");
/*输出参数 out*/
int b;
OutParamMethod(out b);
//输出:out,调用方法后,a=2。
Console.WriteLine($"out,调用方法后,a={b}。");
Console.WriteLine($"------------------------------");
/*参数数组*/
//传入0个参数,方法中是空数组
//输出:传入的参数:
ParamArrayMethod();
//单个单个传入数组
//输出:传入的参数: 1 2 3
ParamArrayMethod(1,2,3);
//传入数组
//输出:传入的参数: 4 5 6
ParamArrayMethod(new int[] { 4, 5, 6 });
Console.WriteLine($"------------------------------");
/*命名参数*/
//不使用命名参数
NameParamMethod(1,2);
//使用命名参数
NameParamMethod(twoParam:2,oneParam:1);
Console.WriteLine($"------------------------------");
/*可选参数*/
//不传入 可选参数
//输出:传入的参数:1 0
OptionalParamMethod(1);
//传入 可选参数
//输出:传入的参数:1 2
OptionalParamMethod(1, 2);
Console.WriteLine($"------------------------------");
Console.WriteLine("键入任何键,退出。。。");
Console.ReadKey();
}
四 方法的重载
- 方法签名:方法名相同,但是参数个数/参数类型不同。(方法返回类型不是方法签名的关注点)
- 重载:方法的几个版本有不同的签名。
- 重载方法:不能仅在方法的返回类型上有区别,也不能仅仅根据参数是声明为out还是ref来区分。
public static void OverloadMethod()
=> Console.WriteLine($"void OverloadMethod()");
public static void OverloadMethod(int one)
=> Console.WriteLine($"void OverloadMethod(int one)");
///// <summary>
///// 返回类型不是签名的一部分
///// </summary>
///// <returns></returns>
//public static bool OverloadMethod()
// => default(bool);
///// <summary>
///// 不能仅仅是参数的传递类型区别
///// </summary>
///// <param name="one"></param>
//public static void OverloadMethod(out int one)
// => Console.WriteLine($"void OverloadMethod(int one)");
五 属性
0.定义
- 它是一个方法或一对方法,在客户端代码看来,它是一个字段。
1.只读/只写属性
- 定义:缺省对应的访问器。
- 这是不好的编程方式,因为这样可能会使客户端代码的作者干到迷惑。一般情况下,如果要用,最好使用一个方法代替。
private string _Name; public string Name { get{return _name} }
2.属性访问器的访问修饰符
- 没有显式指定访问器的访问修饰符,那么默认为属性的访问修饰符级别。
- 在get/set访问器中,必须有一个具备属性的访问级别。 ``` js
private string _Name; public string Name { //protected get{return _Name;}会编译错误, 必须有一个访问器具备属性的访问级别 get{return _Name;} private set{_Name=value} }
#### **3.自动实现属性**
* 如果属性的set/get访问器没有任何逻辑,就可以使用自动实现属性。
* 自动实现属性编译器会自动生成私有字段(语法糖)。
* 每个访问器的访问级别可以不同。但是不能缺省访问器。
``` js
public string Name{get;private set;}
5.属性作为虚字段使用
- 属性的行为与虚字段相似,某些情况下,甚至根本不需要一个支持字段。相反,可以让属性的取值方法放回一个计算好的值,而让赋值方法解析值,并把它持久存储到其他一些成员字段中。所以,属性不允许作为ref或者out参数值使用。
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName
{
get { return FirstName + LastName; }
private set { }
}
六 构造函数
0.构造函数
- 函数名与类名相同,但是没有返回值(返回值不能是void)。
1.默认构造函数:
- 它能把所有的成员字段初始化为类型的默认值。
- 如果类不提供构造函数,编译器会自动生成一个默认的构造函数。
- 如果类提供了构造函数,编译器就不会自动提供默认构造函数。
2.静态构造函数:
- 编写静态构造函数的原因:类有一些静态字段或属性,需要在第一次使用类之前,从外部源中初始化这些字段和属性。
- 静态构造函数只执行一次,即在代码引用类之前调用它,通常在第一次调用类的任何成员之前执行静态构造函数。
- .NET运行库没有确保什么时候执行静态构造函数,也不能预计不同类的静态构造函数的执行顺序。
- 静态构造函数没有访问修饰符,其他C#代码从来不调用它。
- 一个类只能有一个静态构造函数。
3.调用本类的其他构造函数
- 使用this关键字
public class MyClass
{
public static readonly int MaxValue;
/// <summary>
/// 静态构造函数
/// </summary>
static MyClass()
{
MaxValue = 100;
}
public int Age { get; set; }
private int height { get; set; }
public MyClass():this(0,0)
{
}
public MyClass(int age,int height)
{
Age = age;
this.height = height;
}
}