As a learner who transitioned from nursing to programming, I've found that many programming concepts can be understood through nursing work experience. This article will explain several important concepts in C# using real-world scenarios from a hospital information system.
1. Namespaces
A namespace is a way to organize and manage code, similar to a hospital's organizational structure. For example, a hospital is divided into different departments such as Internal Medicine, Surgery, and Nursing, each with its own responsibilities and scope of management. In C#, namespaces serve a similar purpose; they can:
- Avoid naming conflicts (just like different departments in a hospital can have nurses with the same name)
- Provide logical grouping (like a hospital's department divisions)
- Control the access scope of code (similar to a hospital's permission management)
1.1 Namespace Organization Structure
namespace HospitalSystem // The entire hospital system
{
namespace Administration // Administration
{
// Classes for HR management, financial management, etc.
}
namespace Clinical // Clinical Medical
{
namespace Internal // Internal Medicine
{
// Internal Medicine related classes
}
namespace Surgery // Surgery
{
// Surgery related classes
}
}
namespace Nursing // Nursing Department
{
namespace WardManagement // Ward Management
{
// Ward related classes
}
namespace MedicationManagement // Medication Management
{
// Medication related classes
}
}
}
1.2 How to Use Namespaces
- A class is considered to belong to a namespace.
- If the namespace of a class is not present in the current project, you need to manually import the namespace where that class is located:
- Click the Visual Studio prompt with the mouse
- Use the shortcut Alt+Shift+F10
- Remember commonly used namespaces and type them manually.
1.3 Using Namespaces in a Project
// Method 1: Import with using
using HospitalSystem.Nursing;
using HospitalSystem.Pharmacy;
// Method 2: Use fully qualified name
HospitalSystem.Nursing.NursingRecord record = new HospitalSystem.Nursing.NursingRecord();
// Method 3: Use alias
using NurseRecord = HospitalSystem.Nursing.NursingRecord;
1.4 Project Reference Example
Referencing another class in a project:
- Add a reference (e.g., add HospitalCore.dll)
- Reference the namespace
using HospitalCore.Models;
using HospitalCore.Services;
2. Value Types and Reference Types
2.1 Value Types in Detail
Value types store data directly, including:
Integer types
- sbyte: 8-bit signed integer (-128 to 127)
- byte: 8-bit unsigned integer (0 to 255)
- short: 16-bit signed integer
- ushort: 16-bit unsigned integer
- int: 32-bit signed integer (most commonly used)
- uint: 32-bit unsigned integer
- long: 64-bit signed integer
- ulong: 64-bit unsigned integer
Floating-point types
- float: 32-bit single-precision floating point (accurate to 6-9 digits)
- double: 64-bit double-precision floating point (accurate to 15-17 digits)
- decimal: 128-bit high-precision decimal (commonly used for financial calculations)
Other value types
- bool: Boolean (true/false)
- char: 16-bit Unicode character
- enum: Enumeration type
- struct: Structure
Example in a medical system:
public struct VitalSigns
{
public int HeartRate; // Heart rate, typically range 60-100
public decimal Temperature; // Body temperature, precise to one decimal place, e.g., 36.5
public int BloodPressureHigh; // Systolic blood pressure, e.g., 120
public int BloodPressureLow; // Diastolic blood pressure, e.g., 80
public bool IsFever; // Whether fever is present
// Enum example
public enum TemperatureMethod
{
Oral, // Oral temperature
Axillary, // Axillary temperature
Rectal // Rectal temperature
}
public TemperatureMethod Method { get; set; }
// Value type data validation method
public bool IsNormal()
{
return HeartRate >= 60 && HeartRate <= 100
&& Temperature >= 36.0m && Temperature <= 37.2m
&& BloodPressureHigh >= 90 && BloodPressureHigh <= 140
&& BloodPressureLow >= 60 && BloodPressureLow <= 90;
}
}
2.2 Reference Types in Detail
Reference types include:
Class (class)
- All custom classes
- System predefined classes (e.g., String, Object, etc.)
Interface (interface)
Delegate (delegate)
Array (array)
- Regardless of whether the elements are value types or reference types, the array itself is a reference type
String (string)
- Although used frequently, string is a reference type
- Has the special property of immutability
Example in a medical system:
public class PatientRecord
{
// Basic information
public string PatientName { get; set; }
public string IdNumber { get; set; }
public DateTime DateOfBirth { get; set; }
// Diagnosis information (array example)
public string[] Diagnoses { get; set; }
// Medication information (collection example)
public List<Medication> Medications { get; set; }
// Vital signs record (custom class example)
public List<VitalSigns> VitalSignsHistory { get; set; }
// Delegate example - for abnormal vital signs notification
public delegate void VitalSignsAlertHandler(string message);
public event VitalSignsAlertHandler OnVitalSignsAlert;
// Deep copy example
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; }
// Deep copy method
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; }
// Deep copy method
public VitalSigns Clone()
{
return new VitalSigns
{
Temperature = this.Temperature,
HeartRate = this.HeartRate
};
}
}
2.3 Differences in Memory Storage
In C#, memory is divided into two main areas: Stack and Heap:
Stack
- Stores value type data
- Memory allocation and deallocation are automatically managed by the system
- Fast access
- Limited space
- Stored in Last-In-First-Out (LIFO) order
Heap
- Stores the actual data of reference types
- Requires garbage collector (GC) to manage memory
- Larger space but relatively slower access
- More flexible memory allocation and deallocation
Example code:
public class MemoryExample
{
public void DemonstrateMemoryUsage()
{
// Value type example
int temperature = 37; // Allocated directly on the stack, 4 bytes
bool isCritical = true; // Allocated directly on the stack, 1 byte
DateTime checkTime = DateTime.Now; // Although DateTime is a struct, it is still allocated on the stack
// Reference type example
string patientName = "Zhang San"; // String data allocated on the heap, reference stored on the stack
PatientRecord record = new PatientRecord(); // Object on the heap, reference on the stack
// Value type copy example
int temp2 = temperature; // Creates a new independent copy on the stack
temp2 = 38; // Modifying temp2 does not affect temperature
Console.WriteLine($"Original temperature: {temperature}, New temperature: {temp2}"); // 37, 38
// Reference type copy example
PatientRecord record2 = record; // Copies the reference, both variables point to the same heap object
record2.PatientName = "Li Si"; // Modifying via record2 affects record
Console.WriteLine($"Patient in record: {record.PatientName}"); // Outputs "Li Si"
// String special case example
string str1 = "Test";
string str2 = "Test"; // str2 and str1 point to the same string object (string pool)
string str3 = new string(new char[] { 'T', 'e', 's', 't' }); // Forces creation of a new object
// Array example
int[] temperatures = new int[] { 36, 37, 38 }; // Array object on the heap, elements stored contiguously within the array object
int[] temps2 = temperatures; // Copies the reference
temps2[0] = 39; // Modifying temps2 also affects temperatures
}
// Value type as parameter
public void UpdateTemperature(int temp)
{
temp = 39; // Does not affect the original value
}
// Reference type as parameter
public void UpdatePatient(PatientRecord patient)
{
patient.PatientName = "Wang Wu"; // Affects the original object
}
}
3. String Handling
Strings are used very frequently in medical information systems, such as in medical records and doctor's orders. C# provides a rich set of string handling methods:
3.1 Characteristics of Strings
- Immutability: Strings are immutable; each modification creates a new string object.
- String pool: Identical string literals share the same object.
- Can be treated as a read-only array of char.
3.2 Common String Methods in Detail
public class NursingNoteProcessor
{
public void ProcessNursingNotes()
{
// Nursing note example
string note = " Patient Zhang San, male, 62 years old.\n" +
"Warning: Allergic to penicillin!\n" +
" Temperature 37.2°C, Blood pressure 120/80mmHg ";
// 1. Basic string operations
Console.WriteLine($"Length of record: {note.Length}"); // Get string length
// 2. Whitespace handling
string trimmed = note.Trim(); // Remove leading and trailing spaces
string trimStart = note.TrimStart(); // Remove leading spaces
string trimEnd = note.TrimEnd(); // Remove trailing spaces
// 3. Case conversion
string upper = note.ToUpper(); // Convert to uppercase (used for important warnings)
string lower = note.ToLower(); // Convert to lowercase
// 4. Search operations
bool hasAllergy = note.Contains("Allergic"); // Check if it contains a particular string
int allergyIndex = note.IndexOf("Allergic"); // Find the first occurrence position
int lastIndex = note.LastIndexOf(","); // Find the last occurrence position
// 5. Replace operations
string replaced = note.Replace("Warning", "【Warning】");
string noSpaces = note.Replace(" ", "");
// 6. String splitting
string[] lines = note.Split(new[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
foreach (string line in lines)
{
Console.WriteLine($"Line content: {line.Trim()}");
}
// 7. Substring extraction
int ageStart = note.IndexOf(",") + 1;
int ageEnd = note.IndexOf("years old");
string age = note.Substring(ageStart, ageEnd - ageStart);
Console.WriteLine($"Age: {age}"); // Output: 62
// 8. String comparison
bool isEqual = note.Equals("Other record", StringComparison.OrdinalIgnoreCase); // Case-insensitive comparison
bool startsWith = note.StartsWith("Patient"); // Check start
bool endsWith = note.EndsWith("mmHg"); // Check end
// 9. String concatenation
string[] vitals = { "Temperature: 37.2°C", "Blood pressure: 120/80mmHg", "Heart rate: 75 bpm" };
string summary = string.Join(", ", vitals);
Console.WriteLine($"Vital signs: {summary}");
// 10. String building (for handling large concatenations)
StringBuilder noteBuilder = new StringBuilder();
noteBuilder.AppendLine("Basic patient information:");
noteBuilder.AppendLine($"Name: Zhang San");
noteBuilder.AppendLine($"Age: {age} years old");
noteBuilder.AppendLine($"Vital signs: {summary}");
string finalNote = noteBuilder.ToString();
}
}
4. Inheritance
Inheritance is one of the core concepts of object-oriented programming, with many application scenarios in hospital management systems.
4.1 Basic Concepts of Inheritance
The essence of inheritance:
- Code reuse
- Establishing parent-child relationships between classes
- Achieving polymorphism
Characteristics of inheritance:
- Single root: A class can have only one direct parent class
- Transitivity: A subclass inherits all features of its parent class, including those inherited by the parent class from its own parent
- Subclasses can extend the functionality of the parent class
- Subclasses can override methods of the parent class
4.2 Example of Hospital Employee Inheritance Hierarchy
// Base class: Hospital Employee
public abstract class HospitalEmployee
{
protected string id;
protected string name;
public string Department { get; set; }
public DateTime HireDate { get; set; }
// Constructor
public HospitalEmployee(string id, string name)
{
this.id = id;
this.name = name;
}
// Virtual method - allows subclass override
public virtual string GetDutyDescription()
{
return $"{name} works in {Department}";
}
// Abstract method - subclass must implement
public abstract decimal CalculateSalary();
}
// Nurse class
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 "Junior": baseSalary = 5000M; break;
case "Intermediate": baseSalary = 7000M; break;
case "Senior": baseSalary = 9000M; break;
default: baseSalary = 4000M; break;
}
}
public override string GetDutyDescription()
{
return $"{name} is a {NursingLevel} nurse in {Department}, {Shift} shift";
}
public override decimal CalculateSalary()
{
decimal shiftBonus = Shift == "Night" ? 1000M : 0M;
return baseSalary + shiftBonus;
}
}
// Head Nurse class
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, "Head")
{
TeamMembers = new List<Nurse>();
}
public void AddTeamMember(Nurse nurse)
{
TeamMembers.Add(nurse);
}
public override decimal CalculateSalary()
{
return base.CalculateSalary() + MANAGEMENT_BONUS;
}
// New management method
public string GenerateTeamReport()
{
StringBuilder report = new StringBuilder();
report.AppendLine($"Nursing team report for {Department}");
report.AppendLine($"Head Nurse: {name}");
report.AppendLine($"Team members: {TeamMembers.Count} people");
foreach (var nurse in TeamMembers)
{
report.AppendLine($"- {nurse.GetDutyDescription()}");
}
return report.ToString();
}
}
5. Collections
In a hospital information system, we often need to handle collections of data items, such as patient lists, medication inventory, etc. C# provides various collection types for our use.
5.1 ArrayList in Detail
ArrayList is a non-generic collection that can store objects of any type.
Characteristics:
- Dynamic size: automatically expands capacity
- Can store different types of data
- Requires type casting, lower performance
- Not recommended for new code; prefer generic List
public class PatientListManager
{
private ArrayList patientList = new ArrayList();
public void DemonstrateArrayList()
{
// Add different types of data
patientList.Add("Zhang San"); // String
patientList.Add(new Patient()); // Patient object
patientList.Add(42); // Number
// Capacity and count
Console.WriteLine($"Capacity: {patientList.Capacity}"); // Default 4, doubles as needed
Console.WriteLine($"Actual count: {patientList.Count}");
// Insert element
patientList.Insert(0, "Emergency patient");
// Check containment
bool hasPatient = patientList.Contains("Zhang San");
// Iteration (requires type casting)
foreach (object item in patientList)
{
if (item is Patient patient)
{
Console.WriteLine($"Patient: {patient.Name}");
}
}
// Deletion operations
patientList.Remove("Zhang San"); // Remove a specific element
patientList.RemoveAt(0); // Remove element at specified index
patientList.Clear(); // Clear the collection
}
}
5.2 Hashtable vs Dictionary
Key-value pair collections are common in medical systems, e.g., medication inventory management.
Hashtable (non-generic):
- Keys and values are of type object
- Requires type casting
- Lower performance
- Not recommended for new code
Dictionary<TKey, TValue> (generic):
- Type safe
- Better performance
- Recommended
public class MedicineInventoryManager
{
// Hashtable example (old way)
private Hashtable medicineStockOld = new Hashtable();
// Dictionary example (recommended way)
private Dictionary<string, int> medicineStock = new Dictionary<string, int>();
public void CompareCollections()
{
// Hashtable operations
medicineStockOld.Add("Amoxicillin", 100);
medicineStockOld["Ibuprofen"] = 50;
// Type casting issue example
int oldStock = (int)medicineStockOld["Amoxicillin"]; // Requires explicit casting
// Dictionary operations
medicineStock.Add("Amoxicillin", 100);
medicineStock["Ibuprofen"] = 50;
// Safe value retrieval
if (medicineStock.TryGetValue("Amoxicillin", out int stock))
{
Console.WriteLine($"Amoxicillin stock: {stock}");
}
// Check if key exists
if (medicineStock.ContainsKey("Ibuprofen"))
{
medicineStock["Ibuprofen"] -= 10; // Reduce stock
}
// Iteration comparison
foreach (DictionaryEntry entry in medicineStockOld)
{
Console.WriteLine($"Medication: {entry.Key}, Stock: {entry.Value}");
}
foreach (KeyValuePair<string, int> kvp in medicineStock)
{
Console.WriteLine($"Medication: {kvp.Key}, Stock: {kvp.Value}");
}
// Iterate over keys or values only
foreach (string medicine in medicineStock.Keys)
{
Console.WriteLine($"Medication: {medicine}");
}
// Convert to list
List<string> medicineList = medicineStock.Keys.ToList();
}
}
5.3 List in Detail
List
public class NursingScheduleManager
{
private List<Nurse> nurses = new List<Nurse>();
public void DemonstrateList()
{
// Add elements
nurses.Add(new Nurse("N001", "Nurse Zhang", "Junior"));
nurses.Add(new Nurse("N002", "Nurse Li", "Intermediate"));
// Batch add
var newNurses = new List<Nurse>
{
new Nurse("N003", "Nurse Wang", "Senior"),
new Nurse("N004", "Nurse Zhao", "Intermediate")
};
nurses.AddRange(newNurses);
// Search operations
Nurse foundNurse = nurses.Find(n => n.NursingLevel == "Intermediate");
List<Nurse> juniorNurses = nurses.FindAll(n => n.NursingLevel == "Junior");
// Sorting
nurses.Sort((n1, n2) => n1.NursingLevel.CompareTo(n2.NursingLevel));
// LINQ operations
var dayShiftNurses = nurses.Where(n => n.Shift == "Day").ToList();
var nurseCount = nurses.Count(n => n.NursingLevel == "Intermediate");
var orderedNurses = nurses.OrderBy(n => n.Name).ToList();
// Transformation
var nurseNames = nurses.Select(n => n.Name).ToList();
// Condition checking
bool hasNightNurse = nurses.Any(n => n.Shift == "Night");
bool allJunior = nurses.All(n => n.NursingLevel == "Junior");
// Deletion operations
nurses.Remove(foundNurse);
nurses.RemoveAll(n => n.NursingLevel == "Intern");
// Range operations
var someNurses = nurses.GetRange(0, 2); // Get the first two nurses
nurses.RemoveRange(0, 2); // Remove the first two nurses
}
}
6. Type Conversion in Detail
In hospital information systems, type conversions are often used to handle various types of medical staff and medical records.
6.1 Basic Concepts of Type Conversion
- Implicit conversion: Automatic, safe without data loss
- Explicit conversion: Must be done manually, risk of data loss
- Reference type conversion: Type conversion involving inheritance relationships
6.2 Example of Type Conversion in a Medical System
public class StaffManager
{
public void DemonstrateTypeConversion()
{
// Basic type conversion
int heartRate = 75;
double hrDouble = heartRate; // Implicit conversion
decimal hrDecimal = (decimal)hrDouble; // Explicit conversion
// String conversion
string hrString = heartRate.ToString();
int parsedHR = int.Parse("75"); // String to number
// TryParse safe conversion
if (int.TryParse("75", out int result))
{
Console.WriteLine($"Conversion succeeded: {result}");
}
// Reference type conversion example
HospitalEmployee employee = new Nurse("N001", "Nurse Zhang", "Junior");
// 1. is operator - type checking
if (employee is Nurse)
{
Console.WriteLine("This is a nurse");
}
else if (employee is Doctor)
{
Console.WriteLine("This is a doctor");
}
// 2. as operator - safe conversion
Nurse nurse = employee as Nurse;
if (nurse != null)
{
Console.WriteLine($"Nurse level: {nurse.NursingLevel}");
}
// 3. Explicit conversion
try
{
Nurse nurse2 = (Nurse)employee;
Console.WriteLine($"Conversion succeeded: {nurse2.NursingLevel}");
}
catch (InvalidCastException ex)
{
Console.WriteLine($"Conversion failed: {ex.Message}");
}
// 4. Pattern matching (C# 7.0+)
if (employee is Nurse nurseMatch)
{
Console.WriteLine($"Match succeeded: {nurseMatch.NursingLevel}");
}
// 5. Switch pattern matching
string GetEmployeeInfo(HospitalEmployee emp)
{
return emp switch
{
Nurse n => $"Nurse {n.Name}, Level {n.NursingLevel}",
Doctor d => $"Doctor {d.Name}, Specialty {d.Specialty}",
_ => $"Employee {emp.Name}"
};
}
}
// Custom conversion example
public class VitalSignsConverter
{
public static implicit operator string(VitalSigns vs)
{
return $"Temperature: {vs.Temperature}°C, Heart rate: {vs.HeartRate} bpm";
}
public static explicit operator VitalSigns(string data)
{
// Simple example, actual implementation should have more complex parsing logic
var parts = data.Split(',');
return new VitalSigns
{
Temperature = decimal.Parse(parts[0]),
HeartRate = int.Parse(parts[1])
};
}
}
}
6.3 Best Practices for Type Conversion
Prioritize safe conversion methods:
- Use TryParse instead of Parse
- Use the as operator instead of direct type casting
- Always check the conversion result
Handle conversion exceptions:
public decimal ParseTemperature(string temp) { try { return decimal.Parse(temp); } catch (FormatException) { Console.WriteLine("Temperature format is incorrect"); return 0; } catch (OverflowException) { Console.WriteLine("Temperature value is out of range"); return 0; } }
Summary
In this article, we have explored several important concepts in C# using real-world scenarios from a hospital information system:
Namespaces
- Understood the organizational structure of namespaces
- Mastered multiple methods of using namespaces
- Learned project references and namespace imports
Value Types and Reference Types
- Understood the essential differences between the two types
- Mastered different ways memory is stored
- Learned to understand type characteristics through medical data
String Handling
- Mastered common string manipulation methods
- Learned to process medical record text
- Understood the special properties of strings
Inheritance
- Understood the concept of inheritance through the hospital employee hierarchy
- Mastered the characteristics and usage of inheritance
- Learned method overriding and constructor calls
Collections
- Understood the characteristics of different collection types
- Mastered common collection operations
- Learned to choose the appropriate collection type
Type Conversion
- Mastered various type conversion methods
- Learned safe type conversion practices
- Understood the application of type conversion in medical systems
These concepts will help us build more complex medical information system functionalities.