【C#】构造函数实用场景总结
文章目录
- 前言
- 一、构造函数是什么?
- 二、构造函数的用法
- 1.初始化对象,避免无效状态
- 2 初始化静态成员
- 3 构造函数重载
- 4.构造函数链
- 5. 单例模式,多次实例化保持一个对象
- 6. 依赖注入
- 7. 初始化只读对象
前言
构造函数是我们平常编程里经常能碰到的老伙计了,构造函数本质上是类中一种特殊的成员方法,用于在实例化对象的时候,对该类中的一些状态进行初始化。本篇文章总结下工作中经常能碰到的使用构成函数的场景,希望能帮助到大家。
一、构造函数是什么?
构造函数可以理解成一个特殊的方法,当一个类被实例化时,这个构造函数会被自动调用,用作初始化这个对象。但是,构造函数的功能根据应用场景,可以扩展为不同的用法。
二、构造函数的用法
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字段,创建不可变对象,实现线程安全。
代码如上。