C# 定义和组织数据的方法 - Class(类)
·
目录
类的特性(引用类型、可继承、构造函数灵活性等)
一、说明
- 关键字:
class(类默认是引用类型,无需显式声明"只读",但可通过只读属性保持不可变)。 - 构造函数:类允许无参构造函数(按需添加),但示例中仍保留带参数的构造函数以保持数据初始化逻辑。
- 内存特性:类是堆分配的引用类型,赋值时传递引用(而非复制数据),修改副本会影响原实例(需注意与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(需注意空引用异常) |
| 可变性 | 建议不可变(修改需重新创建实例) | 可灵活设计为可变(通过方法修改内部数据) |
| 继承 | 不能继承(仅实现接口) | 可继承和被继承(支持多态) |
| 适用场景 | 轻量、简单、频繁创建的数据(如坐标) | 复杂、需要继承/多态、频繁修改的数据(如订单) |
通过分析,可知道类的灵活性(如允许修改数据、添加扩展方法、支持继承等),适合更复杂的业务场景。
更多推荐
所有评论(0)