Bird
Raised Fist0
C Sharp (C#)programming~15 mins

Property validation logic in C Sharp (C#) - Deep Dive

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Overview - Property validation logic
What is it?
Property validation logic is the process of checking if the values assigned to an object's properties meet certain rules or conditions. It ensures that data stored in an object is correct and meaningful. For example, a person's age property should not be negative. Validation logic helps catch mistakes early and keeps the program reliable.
Why it matters
Without property validation, programs can store wrong or harmful data, leading to bugs, crashes, or wrong results. Imagine a banking app allowing negative balances without checks—it would cause serious problems. Validation protects data integrity and improves user trust by preventing invalid inputs from entering the system.
Where it fits
Before learning property validation, you should understand classes, properties, and basic data types in C#. After mastering validation, you can explore data annotations, custom exceptions, and design patterns like the Validator pattern or Fluent Validation libraries.
Mental Model
Core Idea
Property validation logic acts like a gatekeeper that only allows valid data to enter an object's properties, keeping the object healthy and trustworthy.
Think of it like...
It's like a security guard checking IDs at a club entrance, only letting in people who meet the rules, such as being of legal age.
┌───────────────┐
│   Property    │
│   Setter      │
├───────────────┤
│ Validation?   │───No──> Reject value (error)
│   (Rules)     │
├───────────────┤
│   Accept?     │───Yes──> Store value
└───────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding Properties in C#
🤔
Concept: Introduce what properties are and how they store data in objects.
In C#, properties are like containers inside classes that hold data. They have getters to read the value and setters to change it. For example: public class Person { public string Name { get; set; } } Here, Name is a property that stores a string.
Result
You can create a Person object and assign a name like person.Name = "Alice".
Knowing properties is essential because validation logic usually happens when setting these values.
2
FoundationWhy Validate Property Values?
🤔
Concept: Explain the need to check values before storing them in properties.
Without validation, you might store wrong data, like a negative age or empty name. This can cause errors later. Validation means checking the value before saving it, and rejecting or fixing it if it is wrong.
Result
You understand that validation keeps data meaningful and prevents bugs.
Recognizing the importance of validation motivates writing safer code.
3
IntermediateImplementing Validation in Property Setters
🤔Before reading on: do you think you can put validation code directly inside a property setter? Commit to your answer.
Concept: Show how to add validation code inside the setter of a property.
You can write custom code inside the set block of a property to check the value before saving it. For example: private int age; public int Age { get { return age; } set { if (value < 0) { throw new ArgumentException("Age cannot be negative"); } age = value; } } This code throws an error if someone tries to set a negative age.
Result
Setting Age to -5 causes an error; setting Age to 30 works fine.
Understanding that setters can contain logic allows you to enforce rules directly where data changes.
4
IntermediateUsing Exceptions for Validation Feedback
🤔Before reading on: do you think throwing exceptions is the only way to handle invalid property values? Commit to your answer.
Concept: Introduce throwing exceptions to signal invalid data during validation.
When validation fails, you can throw exceptions like ArgumentException to stop the program flow and inform the caller about the problem. This forces the caller to handle or fix the error. Example: if (string.IsNullOrWhiteSpace(Name)) { throw new ArgumentException("Name cannot be empty"); }
Result
Invalid assignments cause exceptions, preventing bad data from being stored.
Knowing how exceptions work in validation helps you write robust code that fails fast and clearly.
5
IntermediateSeparating Validation Logic from Properties
🤔Before reading on: do you think putting all validation inside property setters is always best? Commit to your answer.
Concept: Explain how to keep validation code separate for cleaner design and reuse.
Instead of putting all checks inside setters, you can create separate methods to validate data. This keeps setters simple and allows reusing validation in other places. Example: private void ValidateAge(int value) { if (value < 0) throw new ArgumentException("Age cannot be negative"); } public int Age { get => age; set { ValidateAge(value); age = value; } }
Result
Validation logic is organized and easier to maintain or extend.
Separating concerns improves code clarity and makes testing validation easier.
6
AdvancedUsing Data Annotations for Declarative Validation
🤔Before reading on: do you think validation can be declared with attributes instead of code? Commit to your answer.
Concept: Introduce data annotations as a way to declare validation rules on properties.
C# supports attributes like [Required], [Range], and [StringLength] to declare validation rules above properties. Example: [Range(0, 120)] public int Age { get; set; } These attributes can be checked automatically by validation frameworks, reducing manual code.
Result
Validation rules are easier to read and maintain, and frameworks can enforce them.
Knowing declarative validation helps you write less code and leverage built-in tools.
7
ExpertCustom Validation with INotifyDataErrorInfo Interface
🤔Before reading on: do you think validation can provide real-time error feedback without exceptions? Commit to your answer.
Concept: Explain how to implement INotifyDataErrorInfo for advanced validation scenarios with error reporting.
INotifyDataErrorInfo lets objects report validation errors asynchronously, useful in UI apps for showing errors as users type. You implement GetErrors and HasErrors methods and raise ErrorsChanged events when validation state changes. This approach avoids exceptions and improves user experience by showing multiple errors at once.
Result
Validation errors can be displayed live in UI without crashing the program.
Understanding this interface unlocks professional-level validation with smooth user feedback.
Under the Hood
When a property setter is called, the runtime executes the code inside the set block. If validation logic is present, it checks the incoming value against rules. If the value is invalid, an exception can be thrown, stopping assignment. Otherwise, the backing field is updated. Data annotations are metadata read by validation frameworks using reflection to enforce rules at runtime or design time.
Why designed this way?
Property setters provide a natural place to control how data is stored, ensuring encapsulation. Throwing exceptions on invalid data enforces correctness immediately. Data annotations were introduced to separate validation rules from logic, making code cleaner and enabling automatic validation by frameworks. Interfaces like INotifyDataErrorInfo were designed to support modern UI needs for responsive validation feedback.
┌───────────────┐
│ Caller sets   │
│ property      │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Property setter│
│ runs validation│
└──────┬────────┘
       │
  Valid?│No
       ▼
┌───────────────┐
│ Throw error or │
│ report error   │
└───────────────┘
       │
      Stop

If Yes:
       │
       ▼
┌───────────────┐
│ Store value in │
│ backing field  │
└───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does throwing exceptions in property setters always improve program reliability? Commit to yes or no.
Common Belief:Throwing exceptions in property setters is always the best way to handle invalid data.
Tap to reveal reality
Reality:Throwing exceptions can be disruptive, especially in UI apps where users expect smooth feedback. Sometimes reporting errors without exceptions is better.
Why it matters:Overusing exceptions can cause poor user experience and harder error handling.
Quick: Can data annotations alone guarantee all validation needs? Commit to yes or no.
Common Belief:Data annotations cover every validation scenario you might need.
Tap to reveal reality
Reality:Data annotations handle common cases but cannot express complex or conditional rules, which require custom code.
Why it matters:Relying only on annotations can lead to missing important validation logic.
Quick: Is it safe to skip validation if you trust the input source? Commit to yes or no.
Common Belief:If input comes from a trusted source, you don't need to validate properties.
Tap to reveal reality
Reality:Trusting input without validation is risky because bugs or malicious data can still occur anywhere.
Why it matters:Skipping validation can cause hidden bugs and security vulnerabilities.
Quick: Does putting validation logic only in setters guarantee all invalid data is caught? Commit to yes or no.
Common Belief:Validation in property setters is enough to ensure all data is valid.
Tap to reveal reality
Reality:Data can be set through other means like constructors or reflection, bypassing setters.
Why it matters:Assuming setters alone protect data can lead to inconsistent object states.
Expert Zone
1
Validation logic in setters can cause issues with object initialization order, so sometimes validation is deferred until after construction.
2
Combining validation with INotifyPropertyChanged requires careful design to avoid infinite loops or inconsistent states.
3
Custom validation frameworks can cache reflection results from data annotations to improve performance in large applications.
When NOT to use
Avoid putting heavy or asynchronous validation logic directly in property setters; instead, use separate validation services or patterns like the Validator pattern. For UI apps, prefer interfaces like INotifyDataErrorInfo over exceptions for better user experience.
Production Patterns
In real-world apps, validation is often layered: basic checks in setters, complex rules in separate validators, and UI feedback via data binding and error notification interfaces. Fluent Validation libraries are popular for expressive, reusable validation rules.
Connections
Encapsulation in Object-Oriented Programming
Property validation logic builds on encapsulation by controlling how data is accessed and modified.
Understanding encapsulation helps grasp why validation belongs inside properties to protect object integrity.
User Interface Design
Validation logic connects to UI design by providing feedback to users about input errors.
Knowing validation helps UI designers create forms that guide users to enter correct data smoothly.
Quality Control in Manufacturing
Both involve checking items against rules before acceptance to ensure quality.
Seeing validation as quality control clarifies its role in preventing defects and maintaining standards.
Common Pitfalls
#1Putting complex validation logic directly in property setters causing slow or blocking operations.
Wrong approach:public string Name { set { // Simulate slow database check System.Threading.Thread.Sleep(5000); if (string.IsNullOrEmpty(value)) throw new ArgumentException("Name required"); name = value; } }
Correct approach:public string Name { set { if (string.IsNullOrEmpty(value)) throw new ArgumentException("Name required"); name = value; } } // Perform slow checks asynchronously elsewhere
Root cause:Misunderstanding that property setters should be fast and simple to avoid blocking program flow.
#2Ignoring validation in constructors leading to invalid objects at creation.
Wrong approach:public Person(string name) { this.name = name; // No validation here }
Correct approach:public Person(string name) { if (string.IsNullOrEmpty(name)) throw new ArgumentException("Name required"); this.name = name; }
Root cause:Assuming property setters are always called during construction, which is not true if fields are assigned directly.
#3Catching exceptions from property setters and ignoring them silently.
Wrong approach:try { person.Age = -1; } catch { } // No error handling or user feedback
Correct approach:try { person.Age = -1; } catch (ArgumentException ex) { Console.WriteLine(ex.Message); }
Root cause:Not understanding that exceptions signal important errors that need proper handling.
Key Takeaways
Property validation logic ensures that only valid data is stored in object properties, protecting program correctness.
Validation can be done inside property setters, but separating logic improves code clarity and reuse.
Throwing exceptions is a common way to signal invalid data, but alternative approaches exist for better user experience.
Data annotations provide a declarative way to specify validation rules, supported by many frameworks.
Advanced validation techniques like INotifyDataErrorInfo enable responsive error reporting in user interfaces.

Practice

(1/5)
1. What is the main purpose of adding validation logic inside a property setter in C#?
easy
A. To check and control the value before saving it to the field
B. To make the property read-only
C. To speed up the program execution
D. To automatically generate a default value

Solution

  1. Step 1: Understand property setters

    Property setters allow you to assign values to private fields through a controlled interface.
  2. Step 2: Role of validation logic

    Validation logic inside the setter checks if the value is valid before saving it, preventing invalid data.
  3. Final Answer:

    To check and control the value before saving it to the field -> Option A
  4. Quick Check:

    Validation in setter = control value before save [OK]
Hint: Validation logic in setter controls data before saving [OK]
Common Mistakes:
  • Thinking validation makes property read-only
  • Assuming validation speeds up code
  • Confusing validation with default value assignment
2. Which of the following is the correct syntax to throw an exception inside a property setter when the value is invalid?
easy
A. set { if (value < 0) throw new Exception("Invalid value"); field = value; }
B. set { if (value < 0) return; field = value; }
C. set { if (value < 0) Console.WriteLine("Invalid"); field = value; }
D. set { if (value < 0) break; field = value; }

Solution

  1. Step 1: Identify correct exception throwing syntax

    Throwing an exception uses the keyword 'throw' followed by 'new Exception(message)'.
  2. Step 2: Check each option

    set { if (value < 0) throw new Exception("Invalid value"); field = value; } correctly throws an exception if value is less than zero. Others use invalid statements like return, Console.WriteLine, or break inside setter.
  3. Final Answer:

    set { if (value < 0) throw new Exception("Invalid value"); field = value; } -> Option A
  4. Quick Check:

    Throw exception = throw new Exception(...) [OK]
Hint: Use 'throw new Exception' to stop invalid values [OK]
Common Mistakes:
  • Using 'return' instead of 'throw' in setter
  • Trying to use 'break' inside setter
  • Only printing error without stopping assignment
3. Consider this C# class snippet:
class Person {
  private int age;
  public int Age {
    get => age;
    set {
      if (value < 0) throw new ArgumentException("Age cannot be negative");
      age = value;
    }
  }
}

What happens if you run this code?
var p = new Person();
p.Age = -5;
medium
A. The age is set to -5 without error
B. An ArgumentException is thrown with message 'Age cannot be negative'
C. The program crashes with a NullReferenceException
D. The setter ignores the negative value and leaves age unchanged

Solution

  1. Step 1: Analyze setter validation

    The setter checks if value is less than 0 and throws ArgumentException if true.
  2. Step 2: Apply to given code

    Setting Age to -5 triggers the exception because -5 < 0.
  3. Final Answer:

    An ArgumentException is thrown with message 'Age cannot be negative' -> Option B
  4. Quick Check:

    Negative age triggers ArgumentException [OK]
Hint: Setter throws exception on invalid input [OK]
Common Mistakes:
  • Assuming negative value is accepted
  • Confusing exception type thrown
  • Thinking setter silently ignores invalid values
4. Identify the error in this property setter code:
private string name;
public string Name {
  get { return name; }
  set {
    if (value == null || value == "")
      throw new ArgumentException("Name cannot be empty");
    name = value;
  }
}
medium
A. The setter does not assign the value to the field
B. The setter should use 'value.Equals("")' instead of 'value == ""'
C. The setter does not check for whitespace-only strings
D. The setter should not throw exceptions in property setters

Solution

  1. Step 1: Review validation logic

    The setter checks if value is null or empty string but does not check if value is whitespace only.
  2. Step 2: Understand missing validation

    Strings like " " (spaces) pass the check but are usually invalid for a name.
  3. Final Answer:

    The setter does not check for whitespace-only strings -> Option C
  4. Quick Check:

    Missing whitespace check in setter validation [OK]
Hint: Check for whitespace with string.IsNullOrWhiteSpace [OK]
Common Mistakes:
  • Thinking '==' is wrong for string comparison here
  • Believing exceptions should never be thrown in setters
  • Forgetting to assign value to field
5. You want to create a property Score that only accepts values between 0 and 100 inclusive. If the value is outside this range, it should throw an ArgumentOutOfRangeException. Which of these implementations correctly applies this validation?
hard
A. private int score; public int Score { get => score; set { if (value < 0 && value > 100) throw new ArgumentOutOfRangeException("Score must be 0-100"); score = value; } }
B. private int score; public int Score { get => score; set { if (value <= 0 && value >= 100) throw new ArgumentOutOfRangeException("Score must be 0-100"); score = value; } }
C. private int score; public int Score { get => score; set { if (value > 0 || value < 100) throw new ArgumentOutOfRangeException("Score must be 0-100"); score = value; } }
D. private int score; public int Score { get => score; set { if (value < 0 || value > 100) throw new ArgumentOutOfRangeException("Score must be 0-100"); score = value; } }

Solution

  1. Step 1: Understand the range condition

    The value must be between 0 and 100 inclusive, so invalid values are less than 0 or greater than 100.
  2. Step 2: Analyze each condition

    private int score; public int Score { get => score; set { if (value < 0 || value > 100) throw new ArgumentOutOfRangeException("Score must be 0-100"); score = value; } } uses 'value < 0 || value > 100' which correctly checks invalid values. Options A, B, and D use incorrect logical operators or conditions.
  3. Final Answer:

    private int score; public int Score { get => score; set { if (value < 0 || value > 100) throw new ArgumentOutOfRangeException("Score must be 0-100"); score = value; } } -> Option D
  4. Quick Check:

    Use '||' for out-of-range checks [OK]
Hint: Use 'if (value < min || value > max)' for range validation [OK]
Common Mistakes:
  • Using '&&' instead of '||' in range checks
  • Reversing comparison operators
  • Throwing wrong exception type