类的特性(引用类型、可继承、构造函数灵活性等)

一、说明

  1. 关键字class(类默认是引用类型,无需显式声明"只读",但可通过只读属性保持不可变)。
  2. 构造函数:类允许无参构造函数(按需添加),但示例中仍保留带参数的构造函数以保持数据初始化逻辑。
  3. 内存特性:类是堆分配的引用类型,赋值时传递引用(而非复制数据),修改副本会影响原实例(需注意与struct的区别)。

二、项目结构

项目文件结构示例:

在这里插入图片描述

三、 class 定义

1. 坐标点(Point2D)类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WinFormClassDemo
{
    //class Point2D
    //{
    //}
    public class Point2D  //  class
    {
        // 只读属性(保持不可变,同struct行为)
        public int X { get; }
        public int Y { get; }

        // 构造函数:初始化坐标
        public Point2D(int x, int y)
        {
            X = x;
            Y = y;
        }

        // 计算两点距离(方法逻辑不变)
        public double DistanceTo(Point2D other)
        {
            if (other == null)  // 类可能为null,需增加空校验(struct不会为null)
                throw new ArgumentNullException(nameof(other), "目标坐标不能为空");

            int dx = X - other.X;
            int dy = Y - other.Y;
            return Math.Sqrt(dx * dx + dy * dy);
        }

        public override string ToString()
        {
            return $"坐标: ({X}, {Y})";
        }
    }
}

2. 用户信息(UserInfo)类

// UserInfo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WinFormClassDemo
{
    //class UserInfo
    //{
    //}
    public class UserInfo  //  class
    {
        public int Id { get; }
        public string Name { get; }
        public int Age { get; }

        public byte[] bValue { get; } //可变字节数组

        // 构造函数:带参数校验
        public UserInfo(int id, string name, int age, byte[] value)
        {
            Id = id;
            Name = name ?? throw new ArgumentNullException(nameof(name), "姓名不能为空");
            Age = age > 0 ? age : throw new ArgumentOutOfRangeException(nameof(age), "年龄必须大于0");
            bValue = value ?? throw new ArgumentNullException(nameof(value), "字节数组不能为空");
        }

        // 类可以添加额外方法(struct也可以,但类更适合扩展)
        public bool IsAdult()
        {
            return Age >= 18;  // 判断是否成年
        }

        public override string ToString()
        {
            return $"用户信息:ID={Id},姓名={Name},年龄={Age}{(IsAdult() ? "成年" : "未成年")},字节数组长度={bValue.Length})";
        }
    }
}

3. 订单明细(OrderItem)类

// OrderItem.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WinFormClassDemo
{
    //class OrderItem
    //{
    //}
    public class OrderItem  //  class
    {
        public int ProductId { get; }
        public string ProductName { get; }
        public decimal UnitPrice { get; }
        public int Quantity { get; private set; }  // 改为可修改(体现类的灵活性)

        // 构造函数
        public OrderItem(int productId, string productName, decimal unitPrice, int quantity)
        {
            ProductId = productId;
            ProductName = productName ?? throw new ArgumentNullException(nameof(productName));
            UnitPrice = unitPrice >= 0 ? unitPrice : throw new ArgumentOutOfRangeException(nameof(unitPrice));
            Quantity = quantity > 0 ? quantity : throw new ArgumentOutOfRangeException(nameof(quantity));
        }

        // 类允许添加修改数据的方法(struct因值类型特性不适合频繁修改)
        public void UpdateQuantity(int newQuantity)
        {
            if (newQuantity <= 0)
                throw new ArgumentOutOfRangeException(nameof(newQuantity), "数量必须大于0");
            Quantity = newQuantity;  // 修改数量(引用类型修改会影响所有引用)
        }

        // 总价(因Quantity可修改,TotalPrice会动态变化)
        public decimal TotalPrice => UnitPrice * Quantity;

        public override string ToString()
        {
            return $"{ProductName}(ID:{ProductId}):{Quantity}件 × {UnitPrice:C} = {TotalPrice:C}";
        }
    }
}

四、WinForm 中使用 class

注意引用类型的特性(如修改实例会影响所有引用它的变量)。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WinFormClassDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            // 初始化DataGridView(设置列标题)
            dgvOrderItems.AutoGenerateColumns = true; // 自动生成列
        }

        private void btnLoadData_Click(object sender, EventArgs e)
        {
            // 1. 坐标点使用(逻辑不变,但需注意null)
            Point2D formLocation = new Point2D(100, 50);
            this.Location = new System.Drawing.Point(formLocation.X, formLocation.Y);
            txtPoint.Text = formLocation.ToString();

            // 2. 用户信息(新增IsAdult()方法的使用)
            try
            {
                byte[] bValue = { 0x01, 0x02, 0x03 };
                UserInfo user = new UserInfo(1001, "张三", 30, bValue);
                user.bValue[0] += 1;
                user.bValue[2] += 1;

                txtUser.Text = user.ToString();  // 会显示"成年"状态
                Console.WriteLine($"{user.bValue.Length}{user.bValue[0]}{user.bValue[1]}{user.bValue[2]}");
            }
            catch (Exception ex)
            {
                MessageBox.Show("用户信息错误:" + ex.Message);
            }

            // 3. 订单明细(可修改数量,体现类的灵活性)
            List<OrderItem> orderItems = new List<OrderItem>
            {
                new OrderItem(1, "笔记本电脑", 5999.99m, 1),
                new OrderItem(2, "无线鼠标", 99.99m, 2),
                new OrderItem(3, "机械键盘", 299.99m, 1)
            };

            // 修改订单数量(引用类型:修改后列表中的实例会同步变化)
            orderItems[1].UpdateQuantity(3);  // 鼠标数量从2→3
            dgvOrderItems.DataSource = orderItems;
        }

        private void btnCalculate_Click(object sender, EventArgs e)
        {
            var orderItems = dgvOrderItems.DataSource as List<OrderItem>;
            if (orderItems == null || orderItems.Count == 0)
            {
                txtTotal.Text = "无订单数据";
                return;
            }

            // 总价计算(因数量可能被修改,结果会动态变化)
            decimal total = orderItems.Sum(item => item.TotalPrice);
            txtTotal.Text = $"订单总价:{total:C}";
        }
    }
}

测试结果:
在这里插入图片描述
在这里插入图片描述

五、struct 与 class 区别

特性struct(值类型)class(引用类型)
内存分配栈(或嵌入到包含类型)堆(引用存于栈)
赋值行为复制完整数据(副本修改不影响原实例)复制引用(副本修改会影响原实例)
空值(null)不可为null(默认值是所有字段的默认值)可赋值为null(需注意空引用异常)
可变性建议不可变(修改需重新创建实例)可灵活设计为可变(通过方法修改内部数据)
继承不能继承(仅实现接口)可继承和被继承(支持多态)
适用场景轻量、简单、频繁创建的数据(如坐标)复杂、需要继承/多态、频繁修改的数据(如订单)

通过分析,可知道类的灵活性(如允许修改数据、添加扩展方法、支持继承等),适合更复杂的业务场景。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐