Syntax

Syntax to recognize, write, and explain.

List 1

Syntax Used in the Application

These are the main syntax patterns used by the app implementation: models, enums, validation, CSV persistence, searching, sorting, archiving, WPF bindings, and deployment files.

using statements and namespace blocks

using System;
using System.Collections.Generic;
using System.Linq;

namespace AnimalRescueManager.Services
{
    public class DataService
    {
    }
}

Explanation: using imports namespaces so class names such as List<T>, DateTime, and LINQ extension methods can be written without their full namespace every time. The namespace groups related classes and prevents naming collisions.

Usage: Put framework imports at the top of each C# file, then wrap the classes in the namespace that matches the folder responsibility.

Example: AnimalRescueManager.Services contains service logic, while AnimalRescueManager.Models contains record types and enums.

classes, partial classes, fields, and constants

public partial class MainPage : Window
{
    private readonly DataService _dataService;
    private int? _editingAnimalId;
}

public class DataService
{
    private const string DateFormat = "dd/MM/yyyy";
}

Explanation: A class defines data and behavior. A partial class lets generated XAML code and hand-written code-behind combine into one class. private readonly stores a dependency that should not be replaced after construction. const stores a compile-time value.

Usage: Use a normal class for models and services, and a partial class for WPF windows whose visual tree is generated from XAML.

Example: MainPage inherits Window, stores one DataService, and tracks whether the form is adding or editing with int?.

constructors and constructor chaining

public DataService()
    : this("animals.csv", "archives.csv")
{
}

public DataService(string filePath, string archivePath)
{
    _filePath = filePath;
    _archivePath = archivePath;
}

Explanation: A constructor runs when an object is created. The : this(...) syntax calls another constructor in the same class so default setup and custom setup share one initialization path.

Usage: Use a parameterless constructor for the normal app path and a parameterized constructor when testing or when a different data path is needed.

Example: new DataService() stores records in default CSV files, while new DataService("test.csv", "test-archive.csv") can point to separate files.

auto-properties and nullable properties

public int Id { get; set; }
public DateTime Birthday { get; set; }
public IdentificationType? IdType { get; set; }
public DateTime? AdoptedDate { get; set; }

Explanation: Auto-properties expose data through generated getter and setter methods. The ? after a value type means the property can either hold a value or null.

Usage: Use normal properties for required model fields and nullable properties for fields that are only known sometimes.

Example: AdoptedDate is nullable because an active animal might not have been adopted yet.

enums and display names

public enum Species
{
    Dog,
    Cat,
    [Display(Name = "Small & Furry")]
    SmallAndFurry
}

Explanation: An enum restricts a value to a named set of choices. [Display] can provide a user-friendly label when the C# identifier cannot contain spaces or symbols.

Usage: Use enums for fixed option lists such as species, gender, vaccine status, and identification type.

Example: The internal value SmallAndFurry can display and save as Small & Furry.

List, arrays, and Dictionary

var animals = new List<Animal>();
animals.Add(animal);
animals.AddRange(archivedAnimals);

private static readonly Dictionary<Species, string[]> ValidBreedOptions =
    new Dictionary<Species, string[]>
{
    { Species.Dog, new[] { "Collie", "Beagle", "Unknown" } }
};

Explanation: List<T> stores a variable-length sequence. An array stores a fixed sequence. Dictionary<TKey,TValue> stores values by key.

Usage: Use lists for loaded records, arrays for fixed breed options, and dictionaries when one value chooses a related list.

Example: ValidBreedOptions[species] returns the allowed breeds for the selected species.

object initializers

return new Animal
{
    Id = 0,
    Species = species,
    Name = NameTextBox.Text,
    Birthday = BirthdayDatePicker.SelectedDate.Value.Date,
    IsArchived = false
};

Explanation: An object initializer creates an object and assigns properties in one readable block.

Usage: Use it when building a complete model from form controls or parsed CSV fields.

Example: The form builds an Animal object before passing it to the service for validation and saving.

guard clauses and exceptions

if (animal == null)
{
    throw new ArgumentNullException(nameof(animal));
}

if (animal.Id <= 0)
{
    throw new ValidationException("Animal ID is required.");
}

Explanation: A guard clause checks invalid input early and stops the method with a clear exception. nameof(animal) returns the variable name as a string safely.

Usage: Put guard clauses at the start of methods that receive model objects, IDs, dates, file paths, or user input.

Example: Removing or archiving an animal requires a positive ID before any file changes happen.

try, catch, and exception filters

try
{
    return ParseAnimal(parts, path, lineNumber, archivedFile);
}
catch (Exception ex) when (ex is ArgumentException || ex is FormatException || ex is OverflowException)
{
    throw new InvalidDataException("Invalid animal record: " + ex.Message, ex);
}

Explanation: try runs code that might fail. catch handles failures. The when filter limits the catch block to specific exception types.

Usage: Use this when low-level parsing errors should be converted into clearer application-level messages.

Example: CSV parsing wraps invalid number, date, and enum values with the file path and line number.

generic methods and constraints

private TEnum GetSelectedEnum<TEnum>(ComboBox comboBox, string fieldName)
    where TEnum : struct
{
    if (comboBox.SelectedValue == null)
    {
        throw new ValidationException(fieldName + " is required.");
    }

    return (TEnum)comboBox.SelectedValue;
}

Explanation: A generic method works with a type supplied by the caller. The where TEnum : struct constraint limits the type argument to value types, which is suitable for enum-like selections in this app.

Usage: Use generics when the same method logic applies to several types without copying code.

Example: The same combo-box helper can read Species, Gender, VaccineStatus, and IdentificationType.

nullable values, GetValueOrDefault, and ternary operators

int id = _editingAnimalId.GetValueOrDefault();
bool hasIdentification = IdentificationCheckBox.IsChecked == true;

IdType = hasIdentification
    ? (IdentificationType?)GetSelectedEnum<IdentificationType>(IdTypeComboBox, "Identification type")
    : null;

IdNumber = hasIdentification ? IdNumberTextBox.Text : string.Empty;
string savedNumber = animal.IdNumber ?? string.Empty;

Explanation: Nullable values can be empty. GetValueOrDefault returns the stored value or a default. The ternary operator chooses between two expressions. The ?? operator chooses a fallback when the left side is null.

Usage: Use these patterns when a form can represent optional values such as editing ID, identification type, adopted date, and archive date.

Example: A new animal has no editing ID, so the form sends ID 0 and the service generates the final ID.

FindIndex, RemoveAt, RemoveAll, and index assignment

int index = activeAnimals.FindIndex(a => a.Id == animal.Id);

if (index < 0)
{
    throw new KeyNotFoundException("No active animal exists with that ID.");
}

activeAnimals[index] = animal;
activeAnimals.RemoveAt(index);
int removed = activeAnimals.RemoveAll(a => a.Id == id);

Explanation: FindIndex locates an item by condition. Index assignment replaces one item. RemoveAt removes by position. RemoveAll removes every matching item and returns the count.

Usage: Use list mutation methods when updating, deleting, archiving, or restoring records loaded from a file.

Example: Editing replaces the existing item at its index, while archiving removes it from active records before adding it to archived records.

String checks, trimming, and case-insensitive comparison

if (string.IsNullOrWhiteSpace(value))
{
    throw new ValidationException("Value is required.");
}

string normalizedValue = value.Trim();

bool same = string.Equals(
    expected,
    normalizedValue,
    StringComparison.OrdinalIgnoreCase);

Explanation: IsNullOrWhiteSpace checks null, empty, and whitespace-only strings. Trim removes leading and trailing whitespace. string.Equals with OrdinalIgnoreCase compares text without casing differences.

Usage: Use these helpers for user-entered text, CSV values, enum display names, search, and validation.

Example: Breed validation accepts collie and stores the canonical value Collie.

Application syntax

Data Annotation

Data annotations are attributes from System.ComponentModel.DataAnnotations. In this app, they document model rules, identify the key field, describe required values, set display text, and show expected date and range formats.

Reference and using statement

<Reference Include="System.ComponentModel.DataAnnotations" />
using System.ComponentModel.DataAnnotations;

Explanation: The project reference makes the data annotation assembly available at build time. The using statement lets the C# file use attributes such as [Required] and [Display] without writing the full namespace.

Usage: Add the framework reference in the project, then add the using statement at the top of model, enum, service, or converter files that need annotation types.

Example: Animal.cs uses [Key], [Required], [Range], and [DisplayFormat]; Enums.cs uses [Display].

Attribute placement

[Required]
public string Name { get; set; }

[Display(Name = "Small & Furry")]
SmallAndFurry

Explanation: An attribute is placed directly above the class member it describes. For properties, it applies to that model field. For enum values, it applies to that one option.

Usage: Keep each attribute close to the property or enum member so the model rules are readable during code review.

Example: [Required] above Name documents that every animal needs a name, while [Display] above SmallAndFurry gives the UI and CSV code a friendly label.

[Key] and [Required]

[Key]
public int Id { get; set; }

[Required]
public Species Species { get; set; }

[Required]
public string Colour { get; set; }

Explanation: [Key] marks the identity property for a model. [Required] marks a field that must be present for a complete record.

Usage: Use [Key] on the generated ID and [Required] on values the form and CSV file must always provide.

Example: The service still validates required text at runtime, but the annotations make the model's intent visible immediately.

[Range]

[Required]
[Range(0, 300)]
public decimal AdoptionFee { get; set; }

Explanation: [Range] documents the minimum and maximum accepted values for a numeric property.

Usage: Use it for numeric limits that are part of the model contract, especially money, counts, ratings, or percentages.

Example: The adoption fee is calculated as 100, 200, or 300, so the annotated range records that the value should stay between 0 and 300.

[Display]

public enum VaccineStatus
{
    [Display(Name = "Up to date")]
    UpToDate,

    Late,
    Unknown
}

Explanation: [Display] provides user-facing text for a property or enum member. It is useful when the C# identifier cannot contain spaces, punctuation, or the exact wording shown to the user.

Usage: Use it on enum values that need friendly labels in combo boxes, grids, and CSV output.

Example: UpToDate can be stored as a clean enum member and displayed as Up to date.

[DisplayFormat]

[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
public DateTime Birthday { get; set; }

[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
public DateTime? ArchiveDate { get; set; }

Explanation: [DisplayFormat] documents how a value should appear when displayed or edited. The date pattern dd/MM/yyyy matches the CSV date format used by the app.

Usage: Use it on date properties that should be presented consistently across model, UI, and storage documentation.

Example: A birthday such as May 4, 2026 is formatted as 04/05/2026.

Annotations versus runtime validation

[Required]
public string Breed { get; set; }

private static string NormalizeRequiredText(string value, string fieldName)
{
    if (string.IsNullOrWhiteSpace(value))
    {
        throw new ValidationException(fieldName + " is required.");
    }

    return value.Trim();
}

Explanation: Data annotations describe the model, but this app still uses explicit service validation before saving. That keeps CSV writes, user edits, and restored records under the same rules.

Usage: Use annotations for model clarity and framework-friendly metadata, then use runtime validation for business rules that must always execute before file changes.

Example: [Required] marks Breed as mandatory, while NormalizeRequiredText trims the actual input and throws a clear error if it is blank.

Application syntax

LINQ patterns used by the app

Where and ToList

return LoadAnimals(_filePath, false)
    .Where(a => !a.IsArchived)
    .ToList();

Explanation: Where keeps only items that match a condition. ToList executes the query and returns a concrete list.

Usage: Use this for filtering active records, archived records, search results, and date-range matches.

Example: The active list excludes records marked as archived.

OrderBy and ThenBy

return GetAllAnimals()
    .OrderBy(a => a.Species)
    .ThenBy(a => a.Name)
    .ToList();

Explanation: OrderBy sets the main sort key. ThenBy breaks ties while keeping the first sort.

Usage: Use this when records must be sorted by category and then by a secondary field.

Example: Animals appear grouped by species and alphabetized by name within each species.

GroupBy, SelectMany, and Take

return GetAllAnimals()
    .GroupBy(a => a.Species)
    .SelectMany(group => group.OrderBy(a => a.Birthday).Take(3))
    .OrderBy(a => a.Species)
    .ThenBy(a => a.Birthday)
    .ToList();

Explanation: GroupBy separates records into groups. SelectMany flattens the selected items from each group back into one list. Take(3) keeps only the first three items.

Usage: Use this for top-N-per-category requirements.

Example: Sorting birthdays ascending makes the oldest animals appear first, then Take(3) keeps the three oldest in each species.

Concat, Select, DefaultIfEmpty, and Max

return activeAnimals
    .Concat(archivedAnimals)
    .Select(a => a.Id)
    .DefaultIfEmpty(0)
    .Max() + 1;

Explanation: Concat joins two sequences. Select projects each object to one value. DefaultIfEmpty(0) prevents an empty-list error. Max finds the largest existing ID.

Usage: Use this to generate the next incrementing ID without reusing archived IDs.

Example: If the largest active or archived ID is 14, the next ID becomes 15.

Any and FirstOrDefault

var remainingAnimals = activeAnimals
    .Where(a => !animalsToArchive.Any(archived => archived.Id == a.Id))
    .ToList();

string canonicalBreed = validBreeds
    .FirstOrDefault(value => string.Equals(value, breed, StringComparison.OrdinalIgnoreCase));

Explanation: Any checks whether at least one item matches. FirstOrDefault returns the first matching item or the default value when nothing matches.

Usage: Use Any for existence checks and FirstOrDefault when finding one optional match.

Example: The archive operation removes records whose IDs were moved, and breed normalization finds the correct capitalization.

Cast and OfType for enums and attributes

foreach (TEnum candidate in Enum.GetValues(typeof(TEnum)).Cast<TEnum>())
{
    string enumName = candidate.ToString();
}

var display = member.GetCustomAttributes(typeof(DisplayAttribute), false)
    .OfType<DisplayAttribute>()
    .FirstOrDefault();

Explanation: Cast<T> converts items from a non-generic sequence to a generic type. OfType<T> keeps only items of a requested type.

Usage: Use these when older reflection APIs return non-generic collections.

Example: Enum parsing checks every enum value, and display conversion reads the optional DisplayAttribute.

Application syntax

CSV and file IO syntax

Create folders and first-run CSV files

string fullPath = Path.GetFullPath(path);
string directory = Path.GetDirectoryName(fullPath);

if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
{
    Directory.CreateDirectory(directory);
}

if (!File.Exists(path) || new FileInfo(path).Length == 0)
{
    File.WriteAllText(path, Header + Environment.NewLine);
}

Explanation: Path safely works with file paths. Directory creates missing folders. File reads and writes file content. FileInfo.Length checks whether an existing file is empty.

Usage: Run this before reading or writing a CSV so the application can start with no existing data files.

Example: A missing animals.csv file is created with the expected header row.

Read all lines and skip a CSV header

var lines = File.ReadAllLines(path);

for (int i = 1; i < lines.Length; i++)
{
    string line = lines[i];

    if (string.IsNullOrWhiteSpace(line))
    {
        continue;
    }

    var parts = ParseCsvLine(line, path, i + 1);
}

Explanation: ReadAllLines returns a string array. Starting the loop at 1 skips the header. continue moves to the next loop item.

Usage: Use this pattern when a text file has one record per line and the first line is labels.

Example: CSV row 2 in the file is index 1 in the array, so errors report i + 1.

Write all CSV rows

var lines = new List<string> { Header };

foreach (var animal in animals.OrderBy(a => a.Id))
{
    ValidateAnimal(animal);
    lines.Add(FormatAnimalToCsv(animal));
}

File.WriteAllLines(path, lines);

Explanation: The code rebuilds the full file from validated objects, then writes every line at once.

Usage: Use this for small flat-file apps where rewriting the file is simpler and safer than editing individual lines.

Example: After adding, editing, removing, archiving, or restoring, the matching CSV file is rewritten from the current list.

Format a record into one CSV line

return FormatCsvLine(new[]
{
    animal.Id.ToString("D8", CultureInfo.InvariantCulture),
    GetEnumCsvValue(animal.Species),
    animal.Birthday.ToString(DateFormat, CultureInfo.InvariantCulture),
    animal.AdoptionFee.ToString("0.##", CultureInfo.InvariantCulture),
    FormatOptionalDate(animal.ArchiveDate)
});

Explanation: A string array stores each field in order. Each value is converted to a predictable text format before joining the line.

Usage: Use this when the save format must stay stable across computers and regional settings.

Example: D8 stores ID 7 as 00000007, and dd/MM/yyyy stores dates consistently.

Escape CSV fields

private static string EscapeCsvField(string value)
{
    if (value == null) value = string.Empty;

    bool requiresQuotes = value.IndexOfAny(new[] { ',', '"', '\r', '\n' }) >= 0;
    value = value.Replace("\"", "\"\"");

    return requiresQuotes ? "\"" + value + "\"" : value;
}

Explanation: CSV fields containing commas or quotes need quotes around the whole field. Quotes inside the field are doubled.

Usage: Run every field through one escaping method before joining with commas.

Example: Brown, white becomes "Brown, white", and Sam "Buddy" becomes "Sam ""Buddy""".

Parse CSV characters with StringBuilder

var fields = new List<string>();
var field = new StringBuilder();
bool inQuotes = false;

for (int i = 0; i < line.Length; i++)
{
    char current = line[i];

    if (current == ',' && !inQuotes)
    {
        fields.Add(field.ToString());
        field.Clear();
    }
    else
    {
        field.Append(current);
    }
}

Explanation: StringBuilder efficiently builds the current field one character at a time. inQuotes tracks whether commas should split fields or be kept as data.

Usage: Use a parser instead of Split(',') when CSV fields may contain commas or quotes.

Example: The parser keeps "Brown, white" as one colour field.

Parse numbers, dates, and booleans

int id = int.Parse(parts[0], NumberStyles.Integer, CultureInfo.InvariantCulture);
decimal fee = decimal.Parse(parts[12], NumberStyles.Number, CultureInfo.InvariantCulture);
DateTime birthday = DateTime.ParseExact(parts[7], "dd/MM/yyyy", CultureInfo.InvariantCulture);

bool parsedBoolean;
if (bool.TryParse(value.Trim(), out parsedBoolean))
{
    return parsedBoolean;
}

Explanation: Parse methods convert strings back to typed values. ParseExact requires the date to match the specified format. TryParse returns a success flag instead of throwing on invalid input.

Usage: Use exact parsing for saved file formats and TryParse for user-entered values.

Example: Remove-by-ID uses int.TryParse so invalid text can show a message without crashing.

Application syntax

WPF, XAML, and code-behind syntax

Window and namespace declarations

<Window x:Class="AnimalRescueManager.Views.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:views="clr-namespace:AnimalRescueManager.Views"
        Title="Animal Rescue Manager"
        Height="720"
        Width="1100">
</Window>

Explanation: x:Class connects the XAML file to its C# partial class. XML namespaces enable WPF controls, XAML language features, and local converter classes.

Usage: Use this at the top of every WPF window. Keep x:Class aligned with the code-behind namespace and class name.

Example: Moving a window into a Views folder requires updating the namespace and startup path.

Window resources and StaticResource

<Window.Resources>
    <views:EnumDisplayConverter x:Key="EnumDisplayConverter" />
    <views:BooleanYesNoConverter x:Key="BooleanYesNoConverter" />
</Window.Resources>

<DataGridTextColumn Header="Species"
                    Binding="{Binding Species, Converter={StaticResource EnumDisplayConverter}}" />

Explanation: Resources are reusable objects declared in XAML. StaticResource looks up a resource by key.

Usage: Use resources for converters or styles that multiple controls need.

Example: Grid columns use converters to show enum display names and Yes/No text.

Grid rows, columns, and attached properties

<Grid Margin="10">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <TextBox x:Name="NameTextBox" Grid.Row="0" />
    <DataGrid x:Name="ActiveAnimalsGrid" Grid.Row="1" />
</Grid>

Explanation: A Grid lays out controls in rows and columns. Auto sizes to content, while * takes remaining space. Grid.Row places a control in a row.

Usage: Use grids for form layouts, tab content, and pages that need resizable sections.

Example: The animal list page keeps the toolbar at the top and lets the table fill the available height.

Binding and StringFormat

<DataGridTextColumn Header="ID"
                    Binding="{Binding Id, StringFormat={}{0:D8}}" />

<DataGridTextColumn Header="Birthday"
                    Binding="{Binding Birthday, StringFormat={}{0:dd/MM/yyyy}}" />

<DataGridTextColumn Header="Fee"
                    Binding="{Binding AdoptionFee, StringFormat={}{0:C0}}" />

Explanation: Binding connects a control property to a model property. StringFormat controls how the bound value appears.

Usage: Use binding for read-only grid columns and form controls that display model values.

Example: The ID column displays 1 as 00000001 without changing the stored integer.

Event handlers

<Button Content="Search" Click="SearchActiveButton_Click" />
<TextBox x:Name="ActiveSearchTextBox" KeyDown="ActiveSearchTextBox_KeyDown" />
private void SearchActiveButton_Click(object sender, RoutedEventArgs e)
{
    BindActiveAnimals(_dataService.SearchAnimals(ActiveSearchTextBox.Text), "Search complete.");
}

Explanation: XAML event attributes point to C# methods. The method signature includes sender and event arguments.

Usage: Use event handlers to connect buttons, text boxes, date pickers, check boxes, and grid selection changes to app behavior.

Example: Pressing Enter in the search box calls the same method as the Search button.

Control properties in code-behind

ActiveAnimalsGrid.ItemsSource = activeAnimals;
SpeciesComboBox.ItemsSource = CreateEnumOptions<Species>();
SpeciesComboBox.SelectedValue = animal.Species;
BirthdayDatePicker.SelectedDate = DateTime.Today;
NameTextBox.Clear();

Explanation: Named XAML controls become fields available in code-behind after InitializeComponent runs.

Usage: Update ItemsSource to bind lists, SelectedValue to select enum values, and SelectedDate for date pickers.

Example: Refreshing the app reads CSV records and assigns the lists to the two grids.

IValueConverter

public class BooleanYesNoConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is bool)
        {
            return (bool)value ? "Yes" : "No";
        }

        return string.Empty;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Binding.DoNothing;
    }
}

Explanation: A converter changes a value before WPF displays it. Binding.DoNothing tells WPF not to update the source for a one-way converter.

Usage: Use converters when the model stores one type but the UI should display another format.

Example: A Boolean stored as true appears as Yes in the grid.

MessageBox and dialog results

var result = MessageBox.Show(
    "Remove this animal?",
    "Remove Animal",
    MessageBoxButton.YesNo,
    MessageBoxImage.Warning);

if (result != MessageBoxResult.Yes)
{
    return;
}

Explanation: MessageBox.Show displays a modal dialog and can return which button the user selected.

Usage: Use confirmation dialogs before destructive actions and information/error dialogs for feedback.

Example: Remove selected asks for confirmation before deleting the record from the active CSV.

List 2

Useful Syntax Within the 2026 Scope and Example Test

These patterns are useful beyond the current implementation because they map to the required areas: variables, file IO, algorithms, arrays and lists, control structures, object-oriented programming, Windows or console apps, end-to-end development, deployment files, and basic relational data design.

Variables and common data types

int id = 1;
decimal adoptionFee = 200m;
bool isArchived = false;
string name = "Milo";
DateTime birthday = new DateTime(2022, 5, 10);

Explanation: Variables store values while the program runs. The type controls what values are valid and what operations can be performed.

Usage: Use int for whole-number IDs, decimal for money-like values, bool for yes/no state, string for text, and DateTime for dates.

Example: An archive feature can store bool isArchived and DateTime? archiveDate to separate active records from archived records.

if, else, loops, and switch

if (fee > 300m)
{
    fee = 300m;
}
else if (fee < 0m)
{
    fee = 0m;
}

foreach (var animal in animals)
{
    Console.WriteLine(animal.Name);
}

switch (species)
{
    case Species.Dog:
        break;
    default:
        break;
}

Explanation: Control structures decide which code runs and how many times it runs.

Usage: Use if for validation and branching, loops for processing lists, and switch when one variable has several known cases.

Example: Fee calculation uses age comparisons to choose young, senior, or standard pricing.

CRUD method skeleton

public void AddAnimal(Animal animal) { }
public List<Animal> GetAllAnimals() { return new List<Animal>(); }
public void UpdateAnimal(Animal animal) { }
public void RemoveAnimal(int id) { }

Explanation: CRUD means create, read, update, and delete. These four operations cover the basic lifecycle of records in a data app.

Usage: Create one service class that owns CRUD behavior, validation, and file saving so the UI does not duplicate business rules.

Example: A Save button can call AddAnimal for a new record or UpdateAnimal for an existing record.

Generated zero-padded IDs

int nextId = animals.Select(a => a.Id).DefaultIfEmpty(0).Max() + 1;
string displayId = nextId.ToString("D8", CultureInfo.InvariantCulture);

Explanation: The stored value can stay numeric while the displayed or saved value is padded with leading zeroes.

Usage: Use this when requirements ask for generated incrementing IDs with a fixed display width.

Example: ID 42 is displayed as 00000042.

Validation method pattern

private static void RequireText(string value, string fieldName)
{
    if (string.IsNullOrWhiteSpace(value))
    {
        throw new ValidationException(fieldName + " is required.");
    }
}

Explanation: A validation helper centralizes repeated checks and keeps error messages consistent.

Usage: Use helpers for required text, valid enum values, valid ranges, date rules, and related-field requirements.

Example: If identification is checked, validate that both identification type and number are present.

Date math for age and archive rules

if (birthday.Date > DateTime.Today.AddYears(-1))
{
    return 300m;
}

if (birthday.Date < DateTime.Today.AddYears(-10))
{
    return 100m;
}

DateTime cutoffDate = DateTime.Today.AddMonths(-3);

Explanation: DateTime.Today gives today without a time component. AddYears and AddMonths move the date backward or forward.

Usage: Use date math for age bands, archive cutoffs, due dates, search ranges, and time-based business rules.

Example: An adopted animal with an adopted date on or before the three-month cutoff can be bulk archived.

Console application entry point

public static void Main(string[] args)
{
    if (args.Length == 0)
    {
        Console.WriteLine("Usage: app add|list|remove");
        return;
    }

    string command = args[0].ToLowerInvariant();
}

Explanation: Main is the entry point for a console app. args contains command-line arguments.

Usage: Use this pattern when the task allows or asks for command-line arguments instead of a graphical UI.

Example: app list could print all active records, while app remove 00000004 could delete by ID.

README Markdown syntax

# Application Name

## Requirements

- Windows
- .NET Framework 4.8

## Build

```powershell
MSBuild.exe AnimalRescueManager.slnx /t:Build /p:Configuration=Release
```

Explanation: Markdown uses headings, lists, and fenced code blocks to document how to build and use a project.

Usage: Include requirements, build commands, run instructions, feature usage, data file format, screenshots, and known limitations.

Example: A reviewer should be able to open the README and run the app without guessing paths or commands.

Test plan table syntax

| Test | Steps | Expected Result |
|---|---|---|
| Add valid animal | Enter all required fields and save | New row appears and reloads after restart |
| Invalid breed | Select a breed not valid for species | Save is blocked with a clear message |

Explanation: A table makes manual test cases easy to scan and repeat.

Usage: Write tests for normal paths, invalid input, boundary values, persistence, search, sort, archive, restore, and deployment.

Example: Test the fee boundaries with animals just below one year, exactly one year, above ten years, and exactly ten years.

Relational database design syntax

CREATE TABLE Animals (
    Id INT PRIMARY KEY,
    Species VARCHAR(40) NOT NULL,
    Name VARCHAR(100) NOT NULL
);

CREATE TABLE Adoptions (
    Id INT PRIMARY KEY,
    AnimalId INT NOT NULL,
    AdoptedDate DATE NOT NULL,
    FOREIGN KEY (AnimalId) REFERENCES Animals(Id)
);

Explanation: Relational design separates data into tables, uses primary keys for identity, and foreign keys for relationships.

Usage: Even when the app uses CSV, know this syntax because relational database design is part of the expected programming knowledge.

Example: Animals and adoptions can be separate tables so one animal record can be linked to adoption history without duplicating animal details.

Scope syntax

Project, build, and deployment syntax

.csproj references and compiled files

<Reference Include="System.ComponentModel.DataAnnotations" />

<Page Include="Views\MainPage.xaml">
  <Generator>MSBuild:Compile</Generator>
  <SubType>Designer</SubType>
</Page>

<Compile Include="Services\DataService.cs" />

Explanation: A project file tells MSBuild which framework references, XAML pages, C# files, resources, and output settings belong to the app.

Usage: Check this file when references are missing, files do not compile, or a moved XAML file is not included correctly.

Example: Adding data annotations requires the framework reference and the matching C# using statement.

WPF startup URI

<Application x:Class="AnimalRescueManager.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="Views/MainPage.xaml">
</Application>

Explanation: StartupUri tells WPF which window to open first.

Usage: Update this when the main window is renamed or moved into a folder.

Example: After moving MainPage.xaml into Views, the startup URI must include Views/.

MSBuild release command

MSBuild.exe AnimalRescueManager.slnx /t:Build /p:Configuration=Release

Explanation: MSBuild.exe builds Visual Studio projects and solutions. /t:Build chooses the build target, and /p:Configuration=Release selects the release configuration.

Usage: Use this from a Developer PowerShell or Developer Command Prompt to produce a release executable.

Example: The release output is expected under the project bin\Release folder.

Dockerfile build syntax

FROM mcr.microsoft.com/dotnet/framework/sdk:4.8-windowsservercore-ltsc2019
WORKDIR /src
COPY . .
RUN MSBuild.exe AnimalRescueManager.slnx /t:Build /p:Configuration=Release
CMD ["cmd", "/c", "dir", "AnimalRescueManager\\bin\\Release"]

Explanation: FROM chooses a base image, WORKDIR sets the working directory, COPY adds project files, RUN executes build commands, and CMD defines the default container command.

Usage: Use a Dockerfile as build evidence or repeatable build automation when allowed by the environment.

Example: A Windows framework SDK image can compile a WPF project, but the GUI should still be run directly on Windows.

Final package checklist syntax

AnimalRescueManager.slnx
AnimalRescueManager/
README.md
LICENSE
Dockerfile
screenshots/
AnimalRescueManager/bin/Release/AnimalRescueManager.exe

Explanation: A deployment package needs source, project files, documentation, evidence, and a working executable.

Usage: Before submission, verify that another person can build, run, and review the app from the included files.

Example: The executable, README, screenshots, source files, project file, and optional Dockerfile should all agree on names and paths.