作为一名从护理行业转行到编程领域的学习者,我发现很多编程概念都可以通过医护工作经验来理解。本文将结合医院信息系统的实际场景,详细讲解 C# 中的几个重要概念。
1. 命名空间
命名空间是一种组织和管理代码的方式,就像医院的组织架构一样。比如医院分为内科、外科、护理部等不同部门,每个部门都有自己的职责和管理范围。在 C# 中,命名空间也起到类似的作用,它可以:
- 避免命名冲突(就像医院里不同科室可以有相同名字的护士)
- 提供逻辑分组(像医院的科室划分)
- 控制代码的访问范围(类似于医院的权限管理)
1.1 命名空间的组织结构
namespace HospitalSystem // 整個醫院系統
{
namespace Administration // 行政管理
{
// 人事管理、財務管理等類別
}
namespace Clinical // 臨床醫療
{
namespace Internal // 內科
{
// 內科相關類別
}
namespace Surgery // 外科
{
// 外科相關類別
}
}
namespace Nursing // 護理部門
{
namespace WardManagement // 病房管理
{
// 病房相關的類別
}
namespace MedicationManagement // 用藥管理
{
// 用藥相關的類別
}
}
}
1.2 命名空间的使用方法
- 可以认为类是属于命名空间的
- 如果在当前项目中没有这个类的命名空间,需要我们手动导入这个类所在的命名空间:
- 使用鼠标点击 Visual Studio 提示
- 使用快捷键 alt+shift+F10
- 记住常用命名空间,手动输入
1.3 在项目中使用命名空间
// 方法1:使用 using 導入
using HospitalSystem.Nursing;
using HospitalSystem.Pharmacy;
// 方法2:使用完整限定名稱
HospitalSystem.Nursing.NursingRecord record = new HospitalSystem.Nursing.NursingRecord();
// 方法3:使用別名
using NurseRecord = HospitalSystem.Nursing.NursingRecord;
1.4 项目引用示例
在一个项目中引用另一个类:
- 添加引用(如添加 HospitalCore.dll)
- 引用命名空间
using HospitalCore.Models;
using HospitalCore.Services;
2. 值类型和引用类型
2.1 值类型详解
值类型直接存储数据本身,包括:
整数类型
- sbyte: 8 位有符号整数 (-128 到 127)
- byte: 8 位无符号整数 (0 到 255)
- short: 16 位有符号整数
- ushort: 16 位无符号整数
- int: 32 位有符号整数(最常用)
- uint: 32 位无符号整数
- long: 64 位有符号整数
- ulong: 64 位无符号整数
浮点类型
- float: 32 位单精度浮点数(精确到 6-9 位)
- double: 64 位双精度浮点数(精确到 15-17 位)
- decimal: 128 位高精度小数(常用于财务计算)
其他值类型
- bool: 布尔值(true/false)
- char: 16 位 Unicode 字符
- enum: 枚举类型
- struct: 结构体
在医疗系统中的应用示例:
public struct VitalSigns
{
public int HeartRate; // 心率,範圍通常60-100
public decimal Temperature; // 體溫,精確到小數點後一位,如36.5
public int BloodPressureHigh; // 收縮壓,如120
public int BloodPressureLow; // 舒張壓,如80
public bool IsFever; // 是否發燒
// 列舉範例
public enum TemperatureMethod
{
Oral, // 口溫
Axillary, // 腋溫
Rectal // 肛溫
}
public TemperatureMethod Method { get; set; }
// 值型別的資料驗證方法
public bool IsNormal()
{
return HeartRate >= 60 && HeartRate <= 100
&& Temperature >= 36.0m && Temperature <= 37.2m
&& BloodPressureHigh >= 90 && BloodPressureHigh <= 140
&& BloodPressureLow >= 60 && BloodPressureLow <= 90;
}
}
2.2 引用类型详解
引用类型包括:
类(class)
- 所有自定义类
- 系统预定义类(如 String, Object 等)
接口(interface)
委托(delegate)
数组(array)
- 无论元素是值类型还是引用类型,数组本身都是引用类型
字符串(string)
- 虽然经常使用,但 string 是引用类型
- 具有特殊的不可变性质
医疗系统示例:
public class PatientRecord
{
// 基本資訊
public string PatientName { get; set; }
public string IdNumber { get; set; }
public DateTime DateOfBirth { get; set; }
// 診斷資訊(陣列範例)
public string[] Diagnoses { get; set; }
// 用藥資訊(集合範例)
public List<Medication> Medications { get; set; }
// 生命徵象記錄(自訂類別範例)
public List<VitalSigns> VitalSignsHistory { get; set; }
// 委派範例 - 用於生命徵象異常通知
public delegate void VitalSignsAlertHandler(string message);
public event VitalSignsAlertHandler OnVitalSignsAlert;
// 深層複製範例
public PatientRecord Clone()
{
var newRecord = new PatientRecord
{
PatientName = this.PatientName,
IdNumber = this.IdNumber,
DateOfBirth = this.DateOfBirth,
Diagnoses = (string[])this.Diagnoses.Clone(),
Medications = this.Medications.Select(m => m.Clone()).ToList(),
VitalSignsHistory = this.VitalSignsHistory.Select(vs => vs.Clone()).ToList()
};
return newRecord;
}
}
public class Medication
{
public string Name { get; set; }
public double Dosage { get; set; }
// 深層複製方法
public Medication Clone()
{
return new Medication
{
Name = this.Name,
Dosage = this.Dosage
};
}
}
public class VitalSigns
{
public decimal Temperature { get; set; }
public int HeartRate { get; set; }
// 深層複製方法
public VitalSigns Clone()
{
return new VitalSigns
{
Temperature = this.Temperature,
HeartRate = this.HeartRate
};
}
}
2.3 内存存储区别详解
在 C# 中,内存分为栈(Stack)和堆(Heap)两个主要区域:
栈(Stack)
- 存储值类型的数据
- 由系统自动管理内存的分配和释放
- 访问速度快
- 空间有限
- 按后进先出(LIFO)的顺序存储
堆(Heap)
- 存储引用类型的实际数据
- 需要垃圾回收器(GC)管理内存
- 空间较大但访问速度相对较慢
- 内存分配和回收更灵活
示例代码:
public class MemoryExample
{
public void DemonstrateMemoryUsage()
{
// 值型別範例
int temperature = 37; // 直接在堆疊上配置4位元組
bool isCritical = true; // 直接在堆疊上配置1位元組
DateTime checkTime = DateTime.Now; // 雖然DateTime是struct,但仍在堆疊上配置
// 參考型別範例
string patientName = "張三"; // 在堆積上配置字串資料,堆疊上儲存參考
PatientRecord record = new PatientRecord(); // 物件在堆積上,參考在堆疊上
// 值型別複製範例
int temp2 = temperature; // 在堆疊上建立新的獨立複本
temp2 = 38; // 修改temp2不影響temperature
Console.WriteLine($"原溫度: {temperature}, 新溫度: {temp2}"); // 37, 38
// 參考型別複製範例
PatientRecord record2 = record; // 複製參考,兩個變數指向同一個堆積上的物件
record2.PatientName = "李四"; // 透過record2修改會影響record
Console.WriteLine($"record的病人: {record.PatientName}"); // 輸出"李四"
// 字串特例範例
string str1 = "測試";
string str2 = "測試"; // str2和str1指向同一個字串物件(字串池)
string str3 = new string(new char[] { '測', '試' }); // 強制建立新物件
// 陣列範例
int[] temperatures = new int[] { 36, 37, 38 }; // 陣列物件在堆積上,元素在陣列物件內連續儲存
int[] temps2 = temperatures; // 複製參考
temps2[0] = 39; // 修改temps2同時影響temperatures
}
// 值型別作為參數
public void UpdateTemperature(int temp)
{
temp = 39; // 不會影響原始值
}
// 參考型別作為參數
public void UpdatePatient(PatientRecord patient)
{
patient.PatientName = "王五"; // 會影響原始物件
}
}
3. 字串处理
字串在医疗信息系统中使用非常频繁,比如病历记录、医嘱记录等。C# 提供了丰富的字串处理方法:
3.1 字串的特性
- 不可变性:字串是不可变的,每次修改都会创建新的字串对象
- 字串池:相同的字串字面量会共享同一个对象
- 可以看作是 char 类型的只读数组
3.2 常用字串方法详解
public class NursingNoteProcessor
{
public void ProcessNursingNotes()
{
// 護理記錄範例
string note = " 患者張三,男,62歲。\n" +
"警告:對青黴素過敏!\n" +
" 體溫37.2℃,血壓120/80mmHg ";
// 1. 基本字串操作
Console.WriteLine($"記錄長度: {note.Length}"); // 取得字串長度
// 2. 空白處理
string trimmed = note.Trim(); // 去除兩端空格
string trimStart = note.TrimStart(); // 去除開頭空格
string trimEnd = note.TrimEnd(); // 去除結尾空格
// 3. 大小寫轉換
string upper = note.ToUpper(); // 轉大寫(用於重要警告)
string lower = note.ToLower(); // 轉小寫
// 4. 尋找操作
bool hasAllergy = note.Contains("過敏"); // 檢查是否包含某字串
int allergyIndex = note.IndexOf("過敏"); // 尋找第一次出現的位置
int lastIndex = note.LastIndexOf(","); // 尋找最後一次出現的位置
// 5. 取代操作
string replaced = note.Replace("警告", "【警告】");
string noSpaces = note.Replace(" ", "");
// 6. 字串分割
string[] lines = note.Split(new[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
foreach (string line in lines)
{
Console.WriteLine($"行內容: {line.Trim()}");
}
// 7. 子字串提取
int ageStart = note.IndexOf(",") + 1;
int ageEnd = note.IndexOf("歲");
string age = note.Substring(ageStart, ageEnd - ageStart);
Console.WriteLine($"年齡: {age}"); // 輸出: 62
// 8. 字串比較
bool isEqual = note.Equals("其他記錄", StringComparison.OrdinalIgnoreCase); // 忽略大小寫比較
bool startsWith = note.StartsWith("患者"); // 檢查開頭
bool endsWith = note.EndsWith("mmHg"); // 檢查結尾
// 9. 字串拼接
string[] vitals = { "體溫: 37.2℃", "血壓: 120/80mmHg", "心率: 75次/分" };
string summary = string.Join(", ", vitals);
Console.WriteLine($"生命徵象: {summary}");
// 10. 字串建置(處理大量字串拼接)
StringBuilder noteBuilder = new StringBuilder();
noteBuilder.AppendLine("患者基本資訊:");
noteBuilder.AppendLine($"姓名:張三");
noteBuilder.AppendLine($"年齡:{age}歲");
noteBuilder.AppendLine($"生命徵象:{summary}");
string finalNote = noteBuilder.ToString();
}
}
4. 继承
继承是面向对象编程的核心概念之一,在医院管理系统中有很多应用场景。
4.1 继承的基本概念
继承的本质:
- 代码重用
- 建立类之间的父子关系
- 实现多态性
继承的特性:
- 单根性:一个类只能有一个直接父类
- 传递性:子类继承父类的所有特性,包括父类从其父类继承的特性
- 子类可以扩展父类的功能
- 子类可以重写父类的方法
4.2 医院员工继承体系示例
// 基底類別:醫院員工
public abstract class HospitalEmployee
{
protected string id;
protected string name;
public string Department { get; set; }
public DateTime HireDate { get; set; }
// 建構函式
public HospitalEmployee(string id, string name)
{
this.id = id;
this.name = name;
}
// 虛擬方法 - 允許子類別覆寫
public virtual string GetDutyDescription()
{
return $"{name}在{Department}工作";
}
// 抽象方法 - 子類別必須實作
public abstract decimal CalculateSalary();
}
// 護士類別
public class Nurse : HospitalEmployee
{
public string NursingLevel { get; set; }
public string Shift { get; set; }
private decimal baseSalary;
public Nurse(string id, string name, string level)
: base(id, name)
{
NursingLevel = level;
SetBaseSalary();
}
private void SetBaseSalary()
{
switch (NursingLevel)
{
case "初級": baseSalary = 5000M; break;
case "中級": baseSalary = 7000M; break;
case "高級": baseSalary = 9000M; break;
default: baseSalary = 4000M; break;
}
}
public override string GetDutyDescription()
{
return $"{name}是{Department}的{NursingLevel}級護士,{Shift}班次";
}
public override decimal CalculateSalary()
{
decimal shiftBonus = Shift == "夜班" ? 1000M : 0M;
return baseSalary + shiftBonus;
}
}
// 主管護士類別
public class HeadNurse : Nurse
{
public List<Nurse> TeamMembers { get; set; }
private const decimal MANAGEMENT_BONUS = 2000M;
public HeadNurse(string id, string name)
: base(id, name, "主管")
{
TeamMembers = new List<Nurse>();
}
public void AddTeamMember(Nurse nurse)
{
TeamMembers.Add(nurse);
}
public override decimal CalculateSalary()
{
return base.CalculateSalary() + MANAGEMENT_BONUS;
}
// 新增的管理方法
public string GenerateTeamReport()
{
StringBuilder report = new StringBuilder();
report.AppendLine($"{Department}護理團隊報告");
report.AppendLine($"主管護士:{name}");
report.AppendLine($"團隊成員:{TeamMembers.Count}人");
foreach (var nurse in TeamMembers)
{
report.AppendLine($"- {nurse.GetDutyDescription()}");
}
return report.ToString();
}
}
5. 集合
在医院信息系统中,我们经常需要处理多个数据项的集合,比如病人列表、药品库存等。C# 提供了多种集合类型供我们使用。
5.1 ArrayList 详解
ArrayList 是一个非泛型集合,可以存储任意类型的对象。
特点:
- 动态大小:自动扩展容量
- 可以存储不同类型的数据
- 需要类型转换,性能较差
- 不建议在新代码中使用,推荐使用泛型 List
public class PatientListManager
{
private ArrayList patientList = new ArrayList();
public void DemonstrateArrayList()
{
// 新增不同類型的資料
patientList.Add("張三"); // 字串
patientList.Add(new Patient()); // 患者物件
patientList.Add(42); // 數字
// 容量和數量
Console.WriteLine($"容量: {patientList.Capacity}"); // 預設4,按需翻倍增長
Console.WriteLine($"實際數量: {patientList.Count}");
// 插入元素
patientList.Insert(0, "急診病人");
// 檢查包含
bool hasPatient = patientList.Contains("張三");
// 走訪(需要型別轉換)
foreach (object item in patientList)
{
if (item is Patient patient)
{
Console.WriteLine($"病人: {patient.Name}");
}
}
// 刪除操作
patientList.Remove("張三"); // 刪除特定元素
patientList.RemoveAt(0); // 刪除指定位置的元素
patientList.Clear(); // 清空集合
}
}
5.2 Hashtable 与 Dictionary 对比
键值对集合在医疗系统中很常用,比如药品库存管理。
Hashtable(非泛型):
- 键和值都是 object 类型
- 需要类型转换
- 性能较差
- 不建议在新代码中使用
Dictionary<TKey, TValue>(泛型):
- 类型安全
- 性能更好
- 推荐使用
public class MedicineInventoryManager
{
// Hashtable範例(舊方式)
private Hashtable medicineStockOld = new Hashtable();
// Dictionary範例(推薦方式)
private Dictionary<string, int> medicineStock = new Dictionary<string, int>();
public void CompareCollections()
{
// Hashtable操作
medicineStockOld.Add("阿莫西林", 100);
medicineStockOld["布洛芬"] = 50;
// 型別轉換問題範例
int oldStock = (int)medicineStockOld["阿莫西林"]; // 需要明確轉換
// Dictionary操作
medicineStock.Add("阿莫西林", 100);
medicineStock["布洛芬"] = 50;
// 安全的值取得
if (medicineStock.TryGetValue("阿莫西林", out int stock))
{
Console.WriteLine($"阿莫西林庫存: {stock}");
}
// 檢查鍵是否存在
if (medicineStock.ContainsKey("布洛芬"))
{
medicineStock["布洛芬"] -= 10; // 減少庫存
}
// 走訪比較
foreach (DictionaryEntry entry in medicineStockOld)
{
Console.WriteLine($"藥品: {entry.Key}, 庫存: {entry.Value}");
}
foreach (KeyValuePair<string, int> kvp in medicineStock)
{
Console.WriteLine($"藥品: {kvp.Key}, 庫存: {kvp.Value}");
}
// 僅走訪鍵或值
foreach (string medicine in medicineStock.Keys)
{
Console.WriteLine($"藥品: {medicine}");
}
// 轉換為清單
List<string> medicineList = medicineStock.Keys.ToList();
}
}
5.3 List详解
List
public class NursingScheduleManager
{
private List<Nurse> nurses = new List<Nurse>();
public void DemonstrateList()
{
// 新增元素
nurses.Add(new Nurse("N001", "張護士", "初級"));
nurses.Add(new Nurse("N002", "李護士", "中級"));
// 批次新增
var newNurses = new List<Nurse>
{
new Nurse("N003", "王護士", "高級"),
new Nurse("N004", "趙護士", "中級")
};
nurses.AddRange(newNurses);
// 查詢操作
Nurse foundNurse = nurses.Find(n => n.NursingLevel == "中級");
List<Nurse> juniorNurses = nurses.FindAll(n => n.NursingLevel == "初級");
// 排序
nurses.Sort((n1, n2) => n1.NursingLevel.CompareTo(n2.NursingLevel));
// LINQ操作
var dayShiftNurses = nurses.Where(n => n.Shift == "白班").ToList();
var nurseCount = nurses.Count(n => n.NursingLevel == "中級");
var orderedNurses = nurses.OrderBy(n => n.Name).ToList();
// 轉換
var nurseNames = nurses.Select(n => n.Name).ToList();
// 檢查條件
bool hasNightNurse = nurses.Any(n => n.Shift == "夜班");
bool allJunior = nurses.All(n => n.NursingLevel == "初級");
// 刪除操作
nurses.Remove(foundNurse);
nurses.RemoveAll(n => n.NursingLevel == "實習");
// 範圍操作
var someNurses = nurses.GetRange(0, 2); // 取得前兩個護士
nurses.RemoveRange(0, 2); // 刪除前兩個護士
}
}
6. 类型转换详解
在医院信息系统中,类型转换经常用于处理不同类型的医护人员和病历记录。
6.1 类型转换的基本概念
- 隐式转换:自动进行,安全无数据丢失
- 显式转换:需要手动进行,可能存在数据丢失风险
- 引用类型转换:涉及继承关系的类型转换
6.2 医疗系统中的类型转换示例
public class StaffManager
{
public void DemonstrateTypeConversion()
{
// 基本型別轉換
int heartRate = 75;
double hrDouble = heartRate; // 隱含轉換
decimal hrDecimal = (decimal)hrDouble; // 明確轉換
// 字串轉換
string hrString = heartRate.ToString();
int parsedHR = int.Parse("75"); // 字串轉數字
// TryParse安全轉換
if (int.TryParse("75", out int result))
{
Console.WriteLine($"轉換成功:{result}");
}
// 參考型別轉換範例
HospitalEmployee employee = new Nurse("N001", "張護士", "初級");
// 1. is運算子 - 檢查型別
if (employee is Nurse)
{
Console.WriteLine("這是一名護士");
}
else if (employee is Doctor)
{
Console.WriteLine("這是一名醫生");
}
// 2. as運算子 - 安全轉換
Nurse nurse = employee as Nurse;
if (nurse != null)
{
Console.WriteLine($"護士級別: {nurse.NursingLevel}");
}
// 3. 明確轉換
try
{
Nurse nurse2 = (Nurse)employee;
Console.WriteLine($"轉換成功: {nurse2.NursingLevel}");
}
catch (InvalidCastException ex)
{
Console.WriteLine($"轉換失敗: {ex.Message}");
}
// 4. 模式比對(C# 7.0+)
if (employee is Nurse nurseMatch)
{
Console.WriteLine($"比對成功: {nurseMatch.NursingLevel}");
}
// 5. switch模式比對
string GetEmployeeInfo(HospitalEmployee emp)
{
return emp switch
{
Nurse n => $"護士 {n.Name}, 級別 {n.NursingLevel}",
Doctor d => $"醫生 {d.Name}, 專科 {d.Specialty}",
_ => $"員工 {emp.Name}"
};
}
}
// 自訂轉換範例
public class VitalSignsConverter
{
public static implicit operator string(VitalSigns vs)
{
return $"體溫: {vs.Temperature}℃, 心率: {vs.HeartRate}次/分";
}
public static explicit operator VitalSigns(string data)
{
// 簡單範例,實際應該有更複雜的解析邏輯
var parts = data.Split(',');
return new VitalSigns
{
Temperature = decimal.Parse(parts[0]),
HeartRate = int.Parse(parts[1])
};
}
}
}
6.3 类型转换最佳实践
优先使用安全的转换方法:
- 使用 TryParse 而不是 Parse
- 使用 as 运算符而不是直接类型转换
- 总是检查转换结果
处理转换异常:
public decimal ParseTemperature(string temp) { try { return decimal.Parse(temp); } catch (FormatException) { Console.WriteLine("溫度格式不正確"); return 0; } catch (OverflowException) { Console.WriteLine("溫度值超出範圍"); return 0; } }
总结
在这篇文章中,我们通过医院信息系统的实际场景,详细探讨了 C# 中的几个重要概念:
命名空间
- 理解了命名空间的组织结构
- 掌握了多种使用命名空间的方法
- 学会了项目引用和命名空间导入
值类型和引用类型
- 理解了两种类型的本质区别
- 掌握了内存存储的不同方式
- 学会了通过医疗数据来理解类型特性
字串处理
- 掌握了常用的字串操作方法
- 学会了处理医疗记录文本
- 理解了字串的特殊性质
继承
- 通过医院员工体系理解继承概念
- 掌握了继承的特性和使用方法
- 学会了方法重写和构造函数调用
集合
- 理解了不同集合类型的特点
- 掌握了集合的常用操作
- 学会了选择合适的集合类型
类型转换
- 掌握了各种类型转换方法
- 学会了安全的类型转换实践
- 理解了类型转换在医疗系统中的应用
这些概念将帮助我们构建更复杂的医疗信息系统功能。