文章目录
前言
构造函数是我们平常编程里经常能碰到的老伙计了,构造函数本质上是类中一种特殊的成员方法,用于在实例化对象的时候,对该类中的一些状态进行初始化。本篇文章总结下工作中经常能碰到的使用构成函数的场景,希望能帮助到大家。
一、构造函数是什么?
构造函数可以理解成一个特殊的方法,当一个类被实例化时,这个构造函数会被自动调用,用作初始化这个对象。但是,构造函数的功能根据应用场景,可以扩展为不同的用法。
二、构造函数的用法
1.初始化对象,避免无效状态
很多时候初始化对象,需要给对象设定一种状态,我哪一种业务逻辑举例。卖出去的商品价格不能为负数,库存数量也不能小于零。
这里构造函数最的作用是保证商品对象在创建时就处于有效状态,避免因价格设置错误,库存数量设置错误导致后续逻辑出错,作为一个业务逻辑的检验之用。
internal class Product
{
public string productId { get; }
/// <summary>
/// 价格 > 0
/// </summary>
public double price { get; }
/// <summary>
/// 库存 > 0
/// </summary>
public int stock { get; }
// 构造函数:初始化+参数校验
public Product(String productId, double price, int stock)
{
this.productId = productId;
// 校验价格合法性,非法则抛出异常,阻止对象创建
if (price < 0)
{
throw new ArgumentOutOfRangeException("商品价格不能为负数:" + price);
}
this.price = price;
// 校验库存合法性
if (stock < 0)
{
throw new ArgumentOutOfRangeException("商品库存不能为负数:" + stock);
}
this.stock = stock;
}
}
2 初始化静态成员
静态变量,静态属性这类成员属于类本身,而非类的实例。它的初始化方式就是通过构造函数初始化的。确保了静态成员在类的整个生命周期中保持一致的初始状态,适合存储全局共享的数据。
比方说一个日志类需要一个属性存放文件目录,用静态属性的方式就很合适,使用构造函数初始化静态成员。
internal class log
{
public static string PhyPath { get; private set; }
static log()
{
PhyPath = AppDomain.CurrentDomain.BaseDirectory;
}
}
3 构造函数重载
构造函数重载允许一个类定义多个构造函数,这些构造函数具有相同的名称但参数不同,包括不限于参数个数,参数类型,参数顺序。这是一种灵活的初始化方式,从而应对实例化的时候的各种场景。
这里提供两种构造函数,一个参数是包含电影名称和描述信息,另一个构造函数只包含电影名称,这样实例化Movie类的时候,就能通过两种方式实例化Movie。为对象提供多种初始化方式,满足不同场景的需求
internal class Movie
{
public int Id { get; set; }
public string MovieName { get; set; }
public string Desc { get; set; }
public Movie(string MovieName)
{
this.MovieName = MovieName;
this.Desc = "";
}
public Movie(string MovieName,string Desc)
{
this.MovieName = MovieName;
this.Desc = Desc;
}
}
4.构造函数链
子类继承父类的时候,子类可以通过base关键字调用父类的构造函数,实现子类向父类传递参数的情况,也能避免重复代码。
比方说我有一个父类,提供一个构造函数,子类可以通过调用父类的构造函数实现状态的配置化。
/// 父类
public BaseClass(String HttpMethod)
{
if (HttpMethod.ToUpper() == "GET")
{
_httpRequest = HttpContext.Current.Request.QueryString;
}
if (HttpMethod.ToUpper() == "POST")
{
_httpRequest = HttpContext.Current.Request.Form;
}
}
/// 子类
public ChiledClass() : base(HttpContext.Current.Request.HttpMethod)
{
}
5. 单例模式,多次实例化保持一个对象
在数据操作这类服务,经常是能碰到使用单例模式的场景。多次实例化一个数据服务对象,返回的任然是同一个实例,禁止外部直接创建对象。这样既能保证资源利用的最大化,并且类能自主控制创建规则,保证代码安全性。
比方说初始化一个RedisServer服务,其构造函数是私有的,无法直接通过初始化的时候执行这个构造函数。通过Lazy这延迟初始化工具,确保RedisServer实例在首次被使用时通过调用内部私有的构造函数创建,实现 “懒加载”。最后通过一个静态实例返回lazy.Value 实现单例模式
/// <summary>
/// Redis单例服务
/// </summary>
public sealed class RedisServer
{
//私有静态字段,存储唯一实例
private static readonly Lazy<RedisServer> lazy = new Lazy<RedisServer>(() => new RedisServer());
/// <summary>
/// 静态实例
/// </summary>
public static RedisServer Instance { get { return lazy.Value; } }
/// <summary>
/// Redis连接对象
/// </summary>
private readonly ConnectionMultiplexer _redis;
/// <summary>
/// Redis数据库对象
/// </summary>
private readonly IDatabase _db;
/// <summary>
/// Redis单例服务
/// </summary>
private RedisServer()
{
/// 逻辑:
/// 1. 创建Redis连接对象
/// 2. 创建Redis数据库对象
}
/// <summary>
/// 获取Redis数据库对象
/// </summary>
public IDatabase GetDatabase()
{
return _db;
}
}
6. 依赖注入
依赖注入中,也可以是通过构造函数来实现接收依赖项的。另外就是这里通过构造函数初始化只读属性,这样可以创建不可变对象,实现线程安全。
[Route("api/[controller]/[action]")]
[ApiController]
public class AuthController : ControllerBase
{
private readonly ILogger<AuthController> _logger;
private readonly IJWTService _jwtService;
public AuthController(ILogger<AuthController> logger = null, IJWTService jwtService = null)
{
_logger = logger;
_jwtService = jwtService;
}
[HttpGet]
public ActionResult<string> test()
{
return "test";
}
[HttpPost]
public ActionResult<string> Login([FromBody]LoginUser loginUser) {
var token = _jwtService.GenerateToken(new CurrentUser() {
UserId = loginUser.UserId,
Name = "张三",
Age = 18,
NickName = "张三",
RoleList = new List<string>() { "admin" } });
return token;
}
}
7. 初始化只读对象
只能在构造函数中初始化readonly字段,创建不可变对象,实现线程安全。
代码如上。

被折叠的 条评论
为什么被折叠?



