构造器(C#)
2016-03-07 16:22
423 查看
一个东西的出现自然是有原因的,就像构造器一样。那为什么会有构造器呢?
首先,类都有默认的构造器,不管你是否显示定义。当我们要读取或赋值类中的属性时,需要先用new操作符实例化一
个类的对象,然后再进行操作。
假如这么一个情况:你实例化类的对象之后,忘了给字段赋值了,而字段恰好没在声明时进行赋值,那么实例化的对
象并没有了实质的意义,因为里面是无效的字段,字段并没有值。一旦这种情况发生的多了,编译器也不警告,那么
会无缘无故占用内存空间,而且让代码很难读懂。
针对以上问题,往往我们没必要依赖默认构造器,我们大可显式定义默认构造器,提供在创建对象时指定必需的数
据。定义构造器就是创建一个方法名与类名完全相同的方法,且方法没有返回类型。
那么有这样一个情形,一个字段在声明时进行了赋值,在构造器内部也进行了赋值。那么最终字段的值以哪个为准
呢?代码执行的顺序是,声明时赋值之后,构造器内部赋值再发生;也就是说构造器赋值会覆盖字段声明时的赋值,
最终生效的是构造器赋值。
与构造器相关的还有对象初始化器(对象初始化列表)和集合初始化器。另外构造器还可以重载,而比构造器重载好一
些的是使用带有附加参数的构造器,可以使用可选参数来替代重载,这样也可以清除地看出"默认"属性的默认值。
有时候在构造器重载时,发现大量的代码都是重复的,所以维护起来也不方便。而完全可以在一个构造器中调用另一
个构造器,避免重复的代码。这样的想法可以用构造器初始化器来实现,成为构造器链。初始化器会在执行当前构造
器实现之前,判断调用另外的哪一个构造器。
请看下面一个例子:
public ConstructorExample()
{
this.InitializeComponent();
Phone phone1 = new Phone("Microsoft",3499);
txtblk1.Text = string.Format("手机1的品牌和价格分别是:{0},{1}元",phone1.Brand,phone1.Price);
//对象初始化器,格式是在构造器后添加一对{},大括号里添加构造器里的属性之外的成员属性,进行初始化
Phone phone2 = new Phone("Nokia", 1799) { MemorySize = "8G",ScreenSize = 5};
txtblk2.Text = string.Format("手机2的品牌和价格分别是:{0},{1}元", phone2.Brand, phone2.Price);
txtblk3.Text = string.Format("手机2的容量和屏幕分别是:{0},{1}寸", phone2.MemorySize, phone2.ScreenSize);
//利用构造器链定义的构造函数
Phone phone3 = new Phone("HTC", 6, "32G", 2399);
txtblk4.Text = string.Format("手机3的品牌和价格分别是:{0},{1}元", phone3.Brand, phone3.Price);
txtblk5.Text = string.Format("手机3的容量和屏幕分别是:{0},{1}寸", phone3.MemorySize, phone3.ScreenSize);
//在下面的构造函数中并没有显式定义phone4对象的MemorySize值,但依旧能输出MemorySize值为16G
Phone phone4 = new Phone("BlackBerry", 4.0);
txtblk6.Text = string.Format("手机3的品牌,屏幕和容量分别是:{0},{1}寸,{2}", phone4.Brand, phone4.ScreenSize,phone4.MemorySize);
Phone phone5 = new Phone("BlackBerry", 4, "4G");
txtblk7.Text = string.Format("手机3的品牌,屏幕和容量分别是:{0},{1}寸,{2}", phone5.Brand, phone5.ScreenSize, phone5.MemorySize);
//集合初始化器
List<Phone> phones = new List<Phone>()
{
new Phone("Microsoft",3499),
new Phone("Nokia",1799),
new Phone("HTC",6,"32G",2399),
new Phone("BlackBerry",4.0),
new Phone("BlackBerry", 4, "4G")
};
}
class Phone
{
public string Brand { get; set; }
public double ScreenSize { get; set; }
public string MemorySize { get; set; }
public int Price { get; set; }
public Phone(string brand,int price)
{
Brand = brand;
Price = price;
}
//构造函数链格式-this:(参数1,参数2...)
public Phone(string brand,double screenSize,string memorySize,int price):this(brand,price)
{
ScreenSize = screenSize;
MemorySize = memorySize;
}
//在一些情况下利用可选参数来代替函数重载更为简洁有效
public Phone(string brand,double screenSize,string memorySize="16G")
{
Brand = brand;
ScreenSize = screenSize;
MemorySize = memorySize;
}
}
结果截图:
首先,类都有默认的构造器,不管你是否显示定义。当我们要读取或赋值类中的属性时,需要先用new操作符实例化一
个类的对象,然后再进行操作。
假如这么一个情况:你实例化类的对象之后,忘了给字段赋值了,而字段恰好没在声明时进行赋值,那么实例化的对
象并没有了实质的意义,因为里面是无效的字段,字段并没有值。一旦这种情况发生的多了,编译器也不警告,那么
会无缘无故占用内存空间,而且让代码很难读懂。
针对以上问题,往往我们没必要依赖默认构造器,我们大可显式定义默认构造器,提供在创建对象时指定必需的数
据。定义构造器就是创建一个方法名与类名完全相同的方法,且方法没有返回类型。
那么有这样一个情形,一个字段在声明时进行了赋值,在构造器内部也进行了赋值。那么最终字段的值以哪个为准
呢?代码执行的顺序是,声明时赋值之后,构造器内部赋值再发生;也就是说构造器赋值会覆盖字段声明时的赋值,
最终生效的是构造器赋值。
与构造器相关的还有对象初始化器(对象初始化列表)和集合初始化器。另外构造器还可以重载,而比构造器重载好一
些的是使用带有附加参数的构造器,可以使用可选参数来替代重载,这样也可以清除地看出"默认"属性的默认值。
有时候在构造器重载时,发现大量的代码都是重复的,所以维护起来也不方便。而完全可以在一个构造器中调用另一
个构造器,避免重复的代码。这样的想法可以用构造器初始化器来实现,成为构造器链。初始化器会在执行当前构造
器实现之前,判断调用另外的哪一个构造器。
请看下面一个例子:
public ConstructorExample()
{
this.InitializeComponent();
Phone phone1 = new Phone("Microsoft",3499);
txtblk1.Text = string.Format("手机1的品牌和价格分别是:{0},{1}元",phone1.Brand,phone1.Price);
//对象初始化器,格式是在构造器后添加一对{},大括号里添加构造器里的属性之外的成员属性,进行初始化
Phone phone2 = new Phone("Nokia", 1799) { MemorySize = "8G",ScreenSize = 5};
txtblk2.Text = string.Format("手机2的品牌和价格分别是:{0},{1}元", phone2.Brand, phone2.Price);
txtblk3.Text = string.Format("手机2的容量和屏幕分别是:{0},{1}寸", phone2.MemorySize, phone2.ScreenSize);
//利用构造器链定义的构造函数
Phone phone3 = new Phone("HTC", 6, "32G", 2399);
txtblk4.Text = string.Format("手机3的品牌和价格分别是:{0},{1}元", phone3.Brand, phone3.Price);
txtblk5.Text = string.Format("手机3的容量和屏幕分别是:{0},{1}寸", phone3.MemorySize, phone3.ScreenSize);
//在下面的构造函数中并没有显式定义phone4对象的MemorySize值,但依旧能输出MemorySize值为16G
Phone phone4 = new Phone("BlackBerry", 4.0);
txtblk6.Text = string.Format("手机3的品牌,屏幕和容量分别是:{0},{1}寸,{2}", phone4.Brand, phone4.ScreenSize,phone4.MemorySize);
Phone phone5 = new Phone("BlackBerry", 4, "4G");
txtblk7.Text = string.Format("手机3的品牌,屏幕和容量分别是:{0},{1}寸,{2}", phone5.Brand, phone5.ScreenSize, phone5.MemorySize);
//集合初始化器
List<Phone> phones = new List<Phone>()
{
new Phone("Microsoft",3499),
new Phone("Nokia",1799),
new Phone("HTC",6,"32G",2399),
new Phone("BlackBerry",4.0),
new Phone("BlackBerry", 4, "4G")
};
}
class Phone
{
public string Brand { get; set; }
public double ScreenSize { get; set; }
public string MemorySize { get; set; }
public int Price { get; set; }
public Phone(string brand,int price)
{
Brand = brand;
Price = price;
}
//构造函数链格式-this:(参数1,参数2...)
public Phone(string brand,double screenSize,string memorySize,int price):this(brand,price)
{
ScreenSize = screenSize;
MemorySize = memorySize;
}
//在一些情况下利用可选参数来代替函数重载更为简洁有效
public Phone(string brand,double screenSize,string memorySize="16G")
{
Brand = brand;
ScreenSize = screenSize;
MemorySize = memorySize;
}
}
结果截图:
相关文章推荐
- C#可选参数的相关使用
- 深入C# 4.0 新特性dynamic、可选参数、命名参数的详细介绍
- 详解C#编程中构造函数的使用
- C++中拷贝构造函数的应用详解
- 完全掌握C++编程中构造函数使用的超级学习教程
- 构造函数不能声明为虚函数的原因及分析
- 深入讲解C++中的构造函数
- C++类成员构造函数和析构函数顺序示例详细讲解
- c++基础语法:构造函数与析构函数
- JavaScript 构造函数 面相对象学习必备知识
- JavaScript面向对象设计二 构造函数模式
- Javascript面向对象编程(二) 构造函数的继承
- 成员初始化列表与构造函数体中的区别详细解析
- JavaScript精炼之构造函数 Constructor及Constructor属性详解
- C#中私有构造函数的特点和用途实例解析
- C#中派生类调用基类构造函数用法分析
- C#静态构造函数用法实例分析
- javascript 静态对象和构造函数的使用和公私问题
- Javascript 使用function定义构造函数
- JavaScript中的普通函数与构造函数比较