昨晚刚刚躺下准备睡觉,我妈敲门说和我爸吵架了,过来跟我挤挤...几分钟之后我爸来让我出去一下,说是要给我妈道歉。我刚走出房门,就听见里边的锁门声...然后我爸说:你去我房里睡吧...过去之后我才知道,原来他们屋里的空调坏了......
========================手动分割线==========================
一、属性
- 由于面向对象的封装特性,通常不会把字段设置成public,就需要我们手动添加为字段赋值的接口;
- 为类中字段手写Get方法和Set方法是很麻烦,所以程序帮我们自动的封装出这个两个方法,也就是添加属性。
1.1 属性的添加
属性的出现的前提是存在私有字段。
1.1.1 添加一个私有字段
private string name;
1.1.2 添加属性
访问修饰符 属性类型 属性名{
get{
返回属性值
}
set {
存储属性值
}
}
- 访问修饰符:约束属性的可见度
- 属性的类型和对应的字段的类型一致
- 属性名与对应的字段名一致,但首字母大写,以便和字段做区分
- get方法:对属性进行取值操作,访问器, 直接返回对应的字段中存储的值
- set方法:对属性进行赋值操作,设置器, 取到隐藏参数value中存储的用户传入的参数,并存储到对应字段中
- value:属性生成的方法,不需要参数,而是使用隐藏参数value取代,value中存储的就是用户传入的所要赋的值
- 属性的优势:提高数据访问的安全性和灵活性。
1.2 番外-属性和字段的区别:
在C#中,我们可以非常自由的、毫无限制的访问公有字段,但在一些场合中,我们可能希望限制只能给字段赋于某个范围的值、或是要求字段只能读或只能写, 或是在改变字段时能改变对象的其他一些状态,这些单靠字段是无法做到的,于是就有了属性,属性中包含两个块:set和get,set块负责属性的写入工作,get块负责属性的读取工作。
在两个块中都可以做一些其他操作,如在set中验证赋的值是否符合要求并决定是否进行赋值。 当缺少其中一块时属性就只能读或只能写,set和get块中属性必需有一个,因为即不能读又不能写的属性是没有意义的。
在上节最后讲到setter和getter方法,那么现在我们来对比下它和属性的区别。
1.2.1 首先有一个私有字段:
class Person
{
private string name;
}
1.2.2 手动添加为字段赋值setter和取值gettter的方法
class Person
{
private string name;
public void SetName(string _name) {
name = _name;
}
public string GetName() {
return name;
}
}
1.2.3 添加属性
class Person
{
private string name;
public string Name {
get {
// 取值方法,直接返回对应的字段中存储的值即可
return name;
}
set {
// 赋值方法,取到隐藏参数value中存储的用户传入的参数,并存储到对应字段中
name = value;
}
}
1.2.4 在set方法中,可以灵活控制赋值条件
class Person
{
private string gender = "妖怪";
public string Gender {
get {
return gender;
}
set {
if (value != "不详") {
return;
}
gender = value;
}
}
}
1.3 属性的使用
在类内部定义好了字段属性后,在Main函数内部调用:
static void Main(string[] args)
{
Person p1 = new Person();
// 使用属性
p1.Name = "妹子";// 调用set方法,赋值操作
Console.WriteLine(p1.Name);// 调用get方法,取值操作
p1.Gender = "不详";
Console.WriteLine(p1.Gender);
p1.Age = 18;
Console.WriteLine(p1.Age);
}
二、数据类型
在C#中,所有的数据类型可划分为两种:
- 值类型:在栈中分配空间,由系统自动分配。
- 引用类型:在堆中分配空间,由程序员用“new”来分配空间
2.1 值类型与引用类型的不同
这两者的不同点主要有以下两点,我们可以从代码效果上去验证。
2.1.1 值类型的第二个变量改变不会影响第一个变量的值,因为两个变量使用的是不同的内存空间
int a = 10;
int b = a;
b++;
Console.WriteLine ("a = " + a);
2.1.2 引用类型的第二个变量的改变,会影响第一个变量的值,因为两个变量使用的是同一块内存空间
int[] arr1 = { 1, 2, 3 };
int[] arr2 = arr1;
arr2 [0] = 4;
arr2 [1] = 5;
for (int i = 0; i < 3; i++) {
Console.Write (arr1 [i] + " ");
}
练习:将冒泡排序封装成方法,在当前类中还有打印输出数组所有元素的方法,随机为数组赋值的方法。并进行验证。
- 定义方法
class SortedClass
{
// 冒泡排序方法
public void SortedArray (int[] arr)
{
int count = arr.Length;
for (int i = 0; i < count - 1; i++) {
for (int j = 0; j < count - 1 - i; j++) {
if (arr [j] > arr [j + 1]) {
int temp = arr [j];
arr [j] = arr [j + 1];
arr [j + 1] = temp;
}
}
}
}
// 输出数字所有元素的方法
public void OutputArray (int[] arr)
{
for (int i = 0; i < arr.Length; i++) {
Console.Write (arr [i] + " ");
}
Console.WriteLine ();
}
// 为数组元素赋随机值的方法
public void RandomArray (int[] arr, int m, int n)
{
int count = arr.Length;
Random ran = new Random ();
for (int i = 0; i < count; i++) {
arr [i] = ran.Next (m, n);
}
}
}
- 调用验证
static void Main(string[] args)
{
int[] array = { 9, 4, 1, 2, 6 };
SortedClass sorted = new SortedClass();
sorted.SortedArray(array);// 进行排序
Console.WriteLine("排序后:");
sorted.OutputArray(array);// 输出排序后的数组
// 定义一个空数组,调用赋值方法,为数组元素赋随机值
int[] temp = new int[10];
sorted.RandomArray(temp, 10, 30);
Console.WriteLine("排序之前的数组:");
sorted.OutputArray(temp);
sorted.SortedArray(temp);
Console.WriteLine("排序后:");
sorted.OutputArray(temp);
}
三、方法的参数
C#中方法的参数有4种类型:
- 值参数:不附加任何修饰符。
- 引用参数:以ref修饰符声明。
- 输出参数:以out修饰符声明,可返回一个或多个值给调用者。
- 可变参数:以params修饰符声明,参数长度可变。
定义一个类MyClass,用来演示方法的参数:
class MyClass
{
// 定义一个方法,用于交换两个变量的值
public void ChangeValue (ref int a, ref int b)
{
int temp = a;
a = b;
b = temp;
}
// 定义一个方法,传入两个浮点数,分别返回这两个数的两倍
public void DoubleOfFloat (float a, float b, out float res1, out float res2)
{
res1 = 2 * a;
res2 = 2 * b;
}
// 定义一个方法,可以用来计算多个整数的和,整数个数可以不做限制
public int Sum (params int[] arr)
{
int sum = 0;
// 在方法内遍历可变参数,得到每一个元素,然后进行处理
foreach (int temp in arr) {
sum += temp;
}
return sum;
}
}
3.1 值参数
- 在开始验证之前,首先在Main函数内对类进行实例化:
MyClass mc = new MyClass ();
- 定义一个方法,用于交换两个整形变量的值(先不添加ref)。因为形式参数的类型为值类型,所以两个变量的值并不会改变
int a = 3, b = 4;
mc.ChangeValue (a, b);
Console.WriteLine ("a = {0}, b = {1}", a, b);
3.2 引用参数 -- ref
- 将刚才定义的方法中的参数加上ref
- ref关键字 定义引用类型的参数(将值类型转变为引用类型)
- 注意:形参和实参前都需要加ref 关键字修饰
- ref修饰的变量在传递参数前一定要有初始值
int a = 3, b = 4;
mc.ChangeValue (ref a, ref b);
Console.WriteLine ("a = {0}, b = {1}", a, b);
3.3 输出参数 -- out
- 方法最多只能有一个返回值,但某些情况下我们可能需要方法执行完以后,给我们返回多个结果,此时就可以使用输出参数out 关键字 修饰输出参数
- 注意:形参和实参前都需要加 out 关键字修饰。被out 修饰的形参,必须在方法体内被赋值
定义一个方法,传入两个浮点数,分别返回这两个数的两倍:
float a = 3.2f, b = 4.9f;
float r1, r2;// 分别定义两个浮点型变量,作为浮点参数
mc.DoubleOfFloat (a, b, out r1, out r2);
Console.WriteLine ("r1 = {0}, r2 = {1}", r1, r2);
3.4 可变参数(必须是数组)-- params
- 定义方法时不能确定调用方法时传递多少个参数,方法中使用遍历数组处理。
- 可变参数的长度可变,长度可以为0
- 可变参数只能使用一次,且放在参数列表的末尾,不能与ref、out同时使用
定义一个方法,可以用来计算多个整数的和,整数个数可以不做限制:
int sum = mc.Sum (6, 8);
Console.WriteLine ("sum = " + sum);
sum = mc.Sum (1, 3, 5, 7, 9);
Console.WriteLine ("sum = " + sum);
sum = mc.Sum (11, 23, 5, 8, 9, 77, 99, 66);
Console.WriteLine ("sum = " + sum);
练习:
1、交换三个整形变量的值(按由小到大的顺序交换),在 Main方法中输出结果。(要求用ref)
2、写一个方法,可以将数组按a[0]-a[1]+a[2]- a[3]+a[4]......的格式返回结果,在Main方法中调用该方法。 (参数要求用params修饰)
(自行练习,做题过程中有疑问可在群内交流。答案见下节。)
本次讲解就到这里,有关技术问题请小伙伴们添加QQ群:941928511,大家一起探讨!
版权声明:本文为博主原创文章,转载请附上原文出处链接和本声明