深入.NET平台和C#编程
第三章
用对象思考:值类型和引用类型
【常量】
有些值在程序的整个过程都不会发生变化
,我们可以把它定义成常量.
常量定义关键字
:const
例
:
public
class Compute
{
const double Pi = 3.14;
//
计算圆的周长
public double Perimeter(double radius)
{
Pi = 3.1415;
return 2 * Pi * radius;
}
//
计算圆的面积
public double Area(double radius)
{
return Pi * radius * radius;
}
}
【枚举】
使用枚举可以避免不合理的赋值
.
例如我们定义一个性别
(string)属性,我们知道这个属性只能接受两个有效值:男和女,如果要其他string类型的值赋给它,编译器也会通过.
枚举定义关键字
:enum
例
:
public
enum Genders
{
Male, Female
}
class
Student
{
///<summary>
///
性别
///</summary>
private Genders gender;
public Genders Gender
{
get { return gender; }
set { gender = value; }
}
}
class
Program
{
static void Main(string[] args)
{
//
使用枚举赋值
Student stu = new Student();
stu.Gender = Genders.Male;
stu.Gender = Genders.Female;
stu.Gender = "
外星人"
; //
编译错误
}
}
枚举还可以用描述性的名称表示整数值
public
enum Genders
{
Male = 0, Female = 1
}
将枚举的值转换成int型,就可以得到定义枚举时所指定的整数值:
int
genderNum = (int)stu.Gender;
在程序中还可以获得它的字符串表示:
Console
.WriteLine("
您输入的是性别是{0}"
, stu.Gender.ToString());
还可以从一个字符串中获取枚举值:
stu.Gender = (Genders)(Enum.Parse(typeof(Genders), "Female"));
Console
.WriteLine("
您输入的是性别是{0}"
, stu.Gender.ToString());
Enum.Parse
方法,第一个参数是关键字typeof(EnumType,”string”),最后使用枚举类型强制转换.
【问题】
枚举的主体中定义属性和方法? 不可以
【结构】
结构和类很相似
,在使用结构时,可以不用NEW,直接定义就可以了,但是必须为结构成员赋初值.定义结构的关键字:struct
struct
StructStudent
{
public string Name;
public Genders Gender;
public int Age;
public string Hobby;
public int Popularity;
public void SayHi()
{
string message;
message = string.Format(
"
大家好,我是{0} 同学,今年{1} 岁了,我喜欢{2}。我的人气值高达{3} !"
,
this.Name, this.Age, this.Hobby, this.Popularity
);
MessageBox.Show(message);
}
}
结构可以有重载有参的构造函数
(C#总是提供结构一个无参的构造函数,所以我们使用结构时不用new):
struct
StructStudent
{
public string Name;
public Genders Gender;
public int Age;
public string Hobby;
public int Popularity;
public StructStudent(string name, Genders gender, int age, string hobby, int popularity)
{
this.Name = name;
this.Gender = gender;
this.Age = age;
this.Hobby = hobby;
this.Popularity = popularity;
}
public void SayHi()
{
string message;
message = string.Format(
"
大家好,我是{0} 同学,今年{1} 岁了,我喜欢{2}。我的人气值高达{3} !"
,
this.Name, this.Age, this.Hobby, this.Popularity
);
MessageBox.Show(message);
}
}
类和结构的差别
:
理解C#中的值类型和引用类型:值类型与引用类型在内存中存储的方式不同
【值类型】
//
使用值类型 student结构
StructStudent
student1 = new StructStudent();
StructStudent
student2 = new StructStudent();
student1.Age = 18;
student2 = student1;
student2.Age = 20;
Console
.WriteLine("student1 = {0},student2 = {1}", student1.Age, student2.Age);
结果
:
student1.Age = 18 , student2.Age = 20
※当student1赋值给student2时, student2对象会保存为student1的值.
※当
student2
的Age赋值20时,就会在student2的区域内存保存Age= 20.
【引用类型】
//
使用引用类型 student类
Student
student1 = new Student();
Student
student2 = new Student();
student1.Age = 18;
student2 = student1;
student2.Age = 20;
Console
.WriteLine("student1 = {0},student2 = {1}", student1.Age, student2.Age);
结果:student1.Age = 20 , student2.Age = 20
※当student1的Age赋值18时,就会在student1的区域内存保存Age= 18.
※将student1赋值给student2时,它们同时引用同一对象, student2的值会保存为student1的值.
※当student2的Age赋值20时,由于它们两个都引用同一对象,所以它们的值都会发生变化.
【装箱与拆箱】
值类型和引用类型可以相互转换,值类型转换为引用类型称为”装箱”,反之称之为”拆箱”.
static
void Main(string[] args)
{
int i = 123;
object
o = i; //
隐式装箱
//
转换为值类型时,所定义的值类型数据与引用类型的数据类型要一致,如果类型错误,会发生异常
//
所以拆箱要注意异常处理
try
{
int j = (int)o; //
拆箱
System.Console.WriteLine("
取消装箱成功."
);
}
catch (System.InvalidCastException e)
{
System.Console.WriteLine("{0}
错误: 不正确的取消装箱."
, e.Message);
}
}
【不同类型的参数传递】
值方式参数传递:
参数是值类型,参数值不会被修改,
参数是引用类型,参数值会被修改.
引用方式参数传递:
参数是值类型/引用类型,参数值都会被修改.
【索引器】
定义一个索引器要使用关键字:this
可以通过重载索引器,从而自定义它的访问方式
public
student_my this[int index]
{
get { return myStu[index]; }
}
索引器实例: 我们定义三个类,学生类,班级类,索引器
///
学生类
/
using
System.Windows.Forms;
namespace
MySchool
{
///<summary>
///
学员类
///</summary>
class student_my
{
//
建立构造函数及方法重载
public student_my():this("student_x",18) { }
public student_my(string name):this(name,18) { }
public student_my(string name, int age)
{
this.name = name;
this.age = age;
}
///<summary>
///
学生姓名
///</summary>
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
///<summary>
///
学员年龄
///</summary>
private int age;
public int Age
{
get { return age; }
set
{
if (age > 1 || age < 100)
{
age = value;
}
else
{
age = 18;
}
}
}
///<summary>
///
自我介绍方法
///</summary>
public void SayHi()
{
string hi = string.Format("
大家好!我叫{0},我今年{1}岁"
,name,age);
MessageBox.Show(hi);
}
}
}
///
班级类
/
namespace
MySchool
{
///<summary>
///
班级类
///</summary>
class Class_my
{
public Class_my(string name)
{
this.Class_name = name;
this.stuIndex = new student_index();
}
///<summary>
///
班级名称
///</summary>
private string class_name;
public string Class_name
{
get { return class_name; }
set { class_name = value; }
}
private student_index stuIndex;
public student_index StuIndex
{
get { return stuIndex; }
set { stuIndex = value; }
}
}
}
///
索引器
/
namespace
MySchool
{
///<summary>
///
学员索引器
///</summary>
class student_index
{
//
建立一个student_my类数组
public student_my[] myStu = new student_my[3];
//
建立一个无参的构造函数,在这里实例化对象
public student_index()
{
myStu[0] = new student_my("
张三"
,29);
myStu[1] = new student_my("
李四"
,23);
myStu[2] = new student_my("
王五"
,18);
}
//
基本索引器根据数组下标查找学员
public student_my this[int index]
{
get { return myStu[index]; }
}
重载的索引器根据姓名查找学员
public student_my this[string name]
{
get
{
int i;
bool found = false;
for ( i = 0; i < myStu.Length; i++)
{
if (myStu[i].Name == name)
{
found = true;
break;
}
}
if (found)
{
return myStu[i];
}
else
{
return null;
}
}
}
}
}
///
索引器演示
/
Class_my
cmy = new Class_my("s1125");
cmy.StuIndex[2].SayHi();
cmy.StuIndex["
张三"
].SayHi();
(
如果有不对的或需要补充的地方
,
还请老师和同学们帮忙指出来
,
谢谢
!)
2010/3/26
整理