【C#】构造函数实用场景总结


前言

构造函数是我们平常编程里经常能碰到的老伙计了,构造函数本质上是类中一种特殊的成员方法,用于在实例化对象的时候,对该类中的一些状态进行初始化。本篇文章总结下工作中经常能碰到的使用构成函数的场景,希望能帮助到大家。

一、构造函数是什么?

构造函数可以理解成一个特殊的方法,当一个类被实例化时,这个构造函数会被自动调用,用作初始化这个对象。但是,构造函数的功能根据应用场景,可以扩展为不同的用法。

二、构造函数的用法

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字段,创建不可变对象,实现线程安全。

代码如上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值