您的位置:首页 > 编程语言 > C#

【C#】面向对象基础—属性、方法、结构

2016-03-07 23:45 1151 查看
一、概念

面向对象不是取代面向过程的:

对象 = {算法 + 数据结构 + ....}
程序 = {对象 + 对象 + ....}

程序是由许多对象构成的,而对象则是一个个的程序实体。

二、属性

1. 属性

属性是一种用于访问对象或类的特性的成员



属性的特点:

 1)属性可以向程序中添加元数据。元数据是嵌入程序中的信息,如编译器指令或者数据描述等。

 2)程序可以使用反射检查自己的元数据。

 3)通常使用属性与COM交互。

 1> 属性的定义

属性以两种方式存在:一种是在公共语言运行库的基类库中定义的属性;另一种是可以创建的,可以向代码中添加附加信息的自定义属性。

[System.Serializable]
public class Person { };
上面的Serializable就是.net Framework类库中定义的属性
自定义属性是在类模块内通过如下方式声明:

属性的访问级别  属性的类型  属性的名称
{
get访问器
set 访问器
}

说明:get访问器与方法体相似,他必须返回属性类型的值;而set访问器类似于返回类型为void的方法,它使用称为value的隐式参数,此参数的类型是属性的类型。

案例:

class Person
{
private int age;
public int Age
{
get
{
return age;
}
set
{
age = value;
}
}

public void SayHello()
{
Console.WriteLine("我的年龄是{0}", Age);
}
}
 2> 属性的使用
程序中使用属性的语法格式是:

对象名.属性名;
注意:属性的访问器是只读还是只写还是可读可写;属性的访问级别。
案例:

namespace _01第一个项目
{
class Program
{
static void Main(string[] args)
{
Person p = new Person();
p.ID = "222H";
Console.WriteLine("用户的编号是{0}", p.ID);
Console.WriteLine();
}
}

class Person
{
public string id = "";
private string name = "";
/// <summary>
/// 定义用户编号,该属性为可读可写属性
/// </summary>

public string ID
{
get
{
return id;
}
set
{
id = value;
}
}
}
}
惯用法:属性的开头字母使用大写,字段的开头字母使用小写;给字段命名的时候要注意的是开头必须加_线。
class Person
{
private int _age;
public int Age
{
get
{
return _age;
}
set
{
_age = value;
}
}

public void SayHello()
{
Console.WriteLine("我的年龄是{0}", Age);
}
}
注意:属性看似字段,其实不是字段,属性可以进行非法值的控制,可以设置只读;get方、set 法的内部其实就是get_****、 set_****
class Person
{
private int age;
public int Age
{
get // 取值
{
return age;
}
set  // 赋值
{
if (value < 0)  // 属性内部进行判断
{
return;
}
this.age = value;  // value代表用户赋过来的值
}
}

public void SayHello()
{
Console.WriteLine("我的年龄是{0}", Age);
}
}

2. 对象的引用

三、方法

1. 概念

方法是一种用于实现可以由对象或类执行的计算机或操作的成员。

方法是包含一序列语句的代码块。

2. 声明

方法在类或结构中,声明时需要制定访问级别、返回值、方法名称及方法参数。(参数可以为空)

一个方法的名称和形参列表定义了改方法的签名,即一个方法的签名由它的名称及其形参的个数、修饰符和类型组成。返回类型不是方法签名的组成部分,形参的名称也不是签名的组成部分。

public void talk();
public int InterSet(int a, int b){};


3. 功能:用来复用代码的。当我们在一个程序中反复的写了同样的代码。拿一般情况下,我们可以把需要重复的代码定义在一个方法中。用的时候只需要调用就行了

4. 方法定义的语法:

[访问修饰符][static]  返回值类型   方法名([参数])
{
方法体;
}
命名规则:方法名开头大写参数名开头小写,参数名、变量名要有意义;
方法的调用:对于静态方法(static修饰的方法)使用 类型.方法名() 调用。如果在同一个类中,可以省略类名,直接写名字调用就行了;

return: 可以立即退出方法;

案例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _01第一个项目
{
class Program
{
static void Main(string[] args)
{
#region  方法调用
outPut();
Console.ReadKey();
#endregion
}
public static void outPut()
{
Console.WriteLine("*************");
Console.WriteLine("*****你好*****");
return;  // 直接退出当前的方法,不会输出下面的这句话
Console.WriteLine("*************");
}
}
}

注意:

 1)方法一般要定义在类中;

 2)如果方法没有返回值,则返回值类型写void;

 3)如果方法没有参数,()不能省略;

5. 变量的作用域

在方法中定义的变量成为局部变量,其作用范围从定义开始,到其所在的大括号结束为止。

被调用者(也就是方法)想得到调用者方法中的参数时,则可以让调用者将参数传给被调用者。(可以通过参数和返回值来实现一个方法去访问另一个方法中的参数)

6、参数

 1>  函数参数默认是值传递,也就是“复制一份”,例子

int age = 20;
IncAge(age);
Console.WriteLine("age = {0}", age);

 2>  定义

public static void Test(int num)
{
//  形参
}
在方法名后面的括号被定义变量,叫做定义这个方法的参数。这里定义的变量用于接收调用者传过来的数据。
注意:如果一个方法一旦有参数,那么调用者就必须传参数,并且传参数的个数、类型与对应位置上的个数、类型必须一致。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _01第一个项目
{
class Program
{
static void Main(string[] args)
{
int a = 3;
// 调用有参的函数
outPut(a);
// 参数的位置于被调用者一样,个数一样
Add(11, 22, "love");
Console.ReadKey();

}
// 自定义方法
public static void outPut(int num)
{
int x = num;
Console.WriteLine(x);
}
// 求和
public static void Add(int a, int b, string name)
{
int num = a + b;
Console.WriteLine(num);
}
}
}

 3> outref讲解

out:则是内部为外部变量赋值,out一般用在函数需要有多个返回值的场所。(大方法中必须对out修饰的传数进行赋值

ref:是可以理解成是双向的,即可以传入,又可以传出。

在传参数的过程中,如果参数有out或ref修饰的话,那么改变方法中参数变量的值,调用者方法中变量的值也会相应改变。


out ref微软注释:https://msdn.microsoft.com/zh-cn/library/t3c3bfhx(v=vs.80).aspx

static void Main(string[] args)
{
//  mainTest();
int number = 100;
test2(ref number);
Console.WriteLine(number);  // 500
Console.WriteLine();
Console.ReadKey();
}
public static void test2(ref int a)
{
int b = a; // 100
a = 520;
}

例如:int.TryParse

namespace _01第一个项目
{
/// <summary>
///
/// </summary>
class Program
{
static void Main(string[] args)
{
//
int number = 10;
int result = test0(number);
Console.WriteLine("number = {0}  result = {1}", number, result);  // number:10 result:20

int number1 = 10;
int result1 = test1(out number);
Console.WriteLine("number1 = {0}  result1 = {1}", number, result);  // number:20 result:20
Console.ReadKey();

}

//
public static int test0(int a)  // 这样,主函数中调用的number并不会改变
{
a = 20;
return a;
}

public static int test1(out int a)  // out是内部为外部变量赋值
{
// a = 20;
// a = a + 1;

a = 20;
return a;
}
}
}
注意:  
 1)在方法的参数类型前加out,那么传参数的时候,也必须在number前加out,表明这个参数不是传入的,而是用来传出的;

 2)如果参数时以out形式传入的,那么在传入前可以不赋初值;

 3)在方法中对于由out修饰的参数,必须赋值并且必须在使用前赋值

编写一个方法:MyTryParse方法,要求用户传入一个字符串,如果这个字符串能转换成int类型,则返回true,并且转换后 的int类型数据通过方法的参数传出。如果字符串不能转换成int类型,则方法返回false,那么out传出的参数将没有意思,在方法中随意赋个值就行了。

namespace _01第一个项目
{
class Program
{
static void Main(string[] args)
{
//
//int number = 10;
//int result = test0(number);
//Console.WriteLine("number = {0}  result = {1}", number, result);  // number:10 result:20

int number1;
int result1 = test1(out number1);
Console.WriteLine("number1 = {0}  result1 = {1}", number1, result1);  // number:20 result:20
// Console.ReadKey();

// string s = "123a";
string s = "123";
int re;
if (IntTryParse(s, out re))  // 如果为真
{
Console.WriteLine("好的: " + re);
}
else
{
Console.WriteLine("转换不行");
}
Console.ReadKey();
}

//
public static int test0(int a)  // 这样,主函数中调用的number并不会改变
{
a = 20;
return a;
}

//
public static int test1(out int a)  // out是内部为外部变量赋值
{
// a = 20;
// a = a + 1;

a = 20;
return a;
}

public static bool IntTryParse(string s, out int result)
{
result = 1;
try
{
result = Convert.ToInt32(s);
return true;
}
catch
{
// result = 1;
return false;
}
}
}
}

7、返回值

 1> 当调用者想访问被调用者(也就是方法中)的变量值的时候,可以通过return返回值来实现;

string s = Console.ReadLine();
int x = Convert.ToInt32("22");
观察上面想想:为什么在方法前面能够定义一个变量接收到方法的值?
那是因为在方法中使用了返回值;只要在方法中返回了值,那么在调用方法中,前面就应该用一个变量来接收方法的返回值。

注意:一个方法有且只有一个返回值。如果一个方法中有返回值,那么在这个方法值中,就必须通过return语句来返回一个数值,并且这个值要与返回值类型相同。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _01第一个项目
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("你确定要关机y/n");
string s = ReadAnswer();
if (s == "y")
{
Console.WriteLine("需要关机");
}
if (s == "n")
{
Console.WriteLine("不需要关机");
}
Console.WriteLine(s);
Console.ReadKey();

}
public static string ReadAnswer()
{
string result = "";
do
{
result = Console.ReadLine();
if (result != "y" && result != "n")
{
Console.WriteLine("输入有误,请重新输入");
}
} while (result != "y" && result != "n");

return result;
}
}
}


四、枚举
1. 常量语法 (与C语言定义类似)
const   类型   常量名  =   变量值;// 在定义时赋值,在其他地方不允许赋值;
2. 枚举
 1> 定义:让我们定义一种枚举类型并且在定义这种类型的时候我们要指定这个类型的所有可能值。
 2> 好处:和用字符串比较起来,用枚举的好处就是限定了变量的取值范围,程序处理起来更方便。
 3> 注意:枚举的定义一般和类定义在同一个级别下。这样,在同一个命名空间下的所有类就可以使用这个枚举了。(方法/类中也可以定义,不过有限制)
 4> 作用:1)限制用户不能随意赋值,只能在定义枚举时候列举的值中选择;  2)不需要死记每一个值是什么,只需要用类型名选择相对应的值就行了。
 5> 警告:
  1)定义枚举时,值不能是int类型;
  2)枚举类型的变量都可以强制转换成一个int类型,意思就是枚举对应的下标编号(从0开始,当然在定义的时候,也是可以将第一个值设置成1开始下标);
  3)枚举的值在定义的时是有一个默认的编号的,编号滴从0开始; 
  4)如果把一个字符串转换成枚举类型
(自枚)(Enum.Parse(typeof(自枚), "待转换的字符串"));


语法:
enum 类型名称 {
值1,
值2,
值N
};   // 注意最后一个不使用符号逗号
枚举案例1:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _01第一个项目
{
/// <summary>
/// 定义了一个类型叫做Gender的枚举类型,值只有两个
/// </summary>
enum Gender
{
man,
woman
} // 注意值不需要加双引号
class Program
{
static void Main(string[] args)
{
#region  枚举
Gender sex;
sex = Gender.man;
Console.WriteLine(int(sex));   // 结果是0
switch (sex)
{
case Gender.man:
Console.WriteLine("男性");
break;

case Gender.woman:
Console.WriteLine("女性");
break;
}
Console.WriteLine(sex);
Console.ReadKey();

#endregion
}
}
}
枚举案例2:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _01第一个项目
{
/// <summary>
/// 定义了一个类型叫做Gender的枚举类型,值只有两个
/// </summary>
enum Gender
{
man,
woman
} // 注意值不需要加双引号
class Program
{
static void Main(string[] args)
{
#region  枚举

// (自枚)(Enum.Parse(typeof(自枚), "待转换的字符串"));
Gender sex;
sex = Gender.man;
string input = Console.ReadLine();  // 输入的字符串

try   // 一般涉及用户自己输入的东西,都会需要使用异常扑捉。
{
sex = (Gender)(Enum.Parse(typeof(Gender), input));  // 输入0 1 不会错
Console.WriteLine("sex是: {0}", sex );
Console.WriteLine("你输入的性别是: " + sex.ToString());
}
catch
{
Console.WriteLine("你输入有误");
}
Console.ReadKey();

#endregion
}
}
}

五、结构体
1. 使用结构体的原因:P122
 1> 当我们需要存储一个人的信息时,要声明一组变量。当我们要存储N个人的信息时,就要声明N组变量,实在是麻烦;
 2> 存储一个人信息的这几个变量间没有关系,容易记乱......
 3> 结构是一种值类型
2. 语法  (与c语言中比较:http://blog.csdn.net/haojie2014/article/details/48160835
访问修饰符 Struct 结构名
{
// 这是与C语言不同的,C语言中结构体是属于面向过程中的知识,并没有访问修饰符,c#是属于面向对象的知识
定义结构成员;  // 注意:定义的结构变量必须要加public修饰符
}


案例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _01第一个项目
{
public struct Person
{
public int Age;
public string Name;
public int Height;
public string Hobby;
}
class Program
{
static void Main(string[] args)
{
Person onePerson;   // C语言中声明结构体变量的话需要加上struct关键字
onePerson.Age = 22;
onePerson.Name = "zhangsan";
}
}
}
案例C语言中的结构体:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

struct Person
{
int age;
int height;
// string name;
};
void ceshi()
{
struct Person stu;
stu.age = 22;
// printf("结果是: %d  \n", 25);
printf("%d", stu.age);
}

void main()
{
ceshi();
printf("你好 \n");
system("pause");
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息