Skip to content

Implementing Success-Driven Value Objects with Functional Programming

A practical guide to implementing type-safe value objects with C# Functorium


You can assign "not-an-email" to string email and the compiler says nothing. You can assign -1 to int age and the same thing happens. Only at runtime does an ArgumentException fire, and only then do you realize, “Oh, I needed validation here too.”

This tutorial solves that problem with the type system. By using Email instead of string and Age instead of int, invalid values simply cannot be created. Starting from a basic division function and progressing to a complete value object framework, you will experience this journey firsthand through 29 hands-on projects.

“Let’s build a world where invalid values in string email are caught at compile time, not at runtime.”

The following table provides recommended learning scopes by experience level.

LevelAudienceRecommended Scope
BeginnerDevelopers who know basic C# syntax and want to get started with functional programmingPart 1 (Chapters 1—6)
IntermediateDevelopers who understand functional concepts and want practical applicationAll of Parts 1—3
AdvancedDevelopers interested in framework design and architectureParts 4—5 + Appendix

After completing this tutorial, you will be able to:

  1. Write safe code using explicit result types instead of exceptions
  2. Express domain rules as types and validate them at compile time
  3. Implement flexible validation logic using Bind/Apply patterns
  4. Develop production-ready value objects using the Functorium framework

Explore why exception-based code is problematic and what alternative success-driven development offers.

Part 1: Understanding Value Object Concepts

Section titled “Part 1: Understanding Value Object Concepts”

Starting from a simple example where 10 / 0 throws, you progress one step at a time through exceptions, defensive programming, functional result types, and always-valid value objects. You verify through code why each step is necessary.

ChTopicKey Learning
1Basic DivisionExceptions vs domain types
2Defensive ProgrammingDefensive programming and precondition validation
3Functional Result TypesFunctional result types (Fin, Validation)
4Always-Valid Value ObjectsImplementing always-valid value objects
5Operator OverloadingOperator overloading and type conversion
6LINQ ExpressionsLINQ expressions and functional composition
7Value EqualityValue equality and hash codes
8ComparabilityComparability and sorting
9Separating Creation and ValidationSeparation of creation and validation
10Validated Value CreationValidated value creation pattern
11Framework TypesFramework types
12Type-Safe EnumerationsType-safe enumerations
13Error CodesStructured error codes
14Fluent Error CodesDomainError helpers
15FluentValidationFluentValidation-based validation patterns
16Architecture TestsArchitecture tests and rules

Validating a single value object is straightforward. However, when you need to validate multiple fields simultaneously and collect all errors at once, you must understand the difference between Bind and Apply.

ChTopicKey Learning
1Sequential Validation (Bind)Sequential validation with Bind
2Parallel Validation (Apply)Parallel validation with Apply
3Combining Apply and BindCombining Apply and Bind
4Inner Bind, Outer ApplyInner Bind with outer Apply
5Inner Apply, Outer BindInner Apply with outer Bind
6Contextual ValidationContextualValidation — field-name-based validation

Assemble the concepts learned in Parts 1—2 into the Functorium framework’s base classes. Complete production-ready patterns from single-value wrappers to composite value objects and type-safe enumerations.

ChTopicFramework Type
1SimpleValueObjectSimpleValueObject<T>
2ComparableSimpleValueObjectComparableSimpleValueObject<T>
3ValueObject (Primitive)ValueObject
4ComparableValueObject (Primitive)ComparableValueObject
5ValueObject (Composite)ValueObject
6ComparableValueObject (Composite)ComparableValueObject
7TypeSafeEnumSmartEnum + IValueObject
8Architecture TestsArchUnitNET
9UnionValueObjectUnionValueObject (Discriminated Union)

Covers real-world issues that arise when integrating value objects with infrastructure like EF Core and CQRS.

ChTopicKey Learning
1Functorium Framework IntegrationIntegrating value objects with the Functorium framework
2ORM Integration PatternsIntegrating value objects with EF Core
3CQRS and Value ObjectsUsing value objects in CQRS patterns
4Testing StrategiesValue object testing strategies

Part 5: Domain-Specific Practical Examples

Section titled “Part 5: Domain-Specific Practical Examples”

See how value objects are used in real domains including e-commerce, finance, user management, and scheduling.

ChTopicValue Object Examples
1E-Commerce DomainMoney, ProductCode, Quantity, OrderStatus
2Finance DomainAccountNumber, InterestRate, ExchangeRate
3User Management DomainEmail, Password, PhoneNumber
4Scheduling DomainDateRange, TimeSlot, Duration

[Part 1] Understanding Value Object Concepts Ch 1: Basic Division -> Ch 2: Defensive Programming -> Ch 3: Functional Result Types -> Ch 4: Always-Valid Value Objects -> Ch 5: Operator Overloading -> Ch 6: LINQ Expressions -> Ch 7: Value Equality -> Ch 8: Comparability -> Ch 9: Separating Creation and Validation -> Ch 10: Validated Value Creation -> Ch 11: Framework Types -> Ch 12: Type-Safe Enumerations -> Ch 13: Error Codes -> Ch 14: Fluent Error Codes -> Ch 15: FluentValidation -> Ch 16: Architecture Tests

[Part 2] Mastering Validation Patterns Ch 1: Sequential Validation (Bind) -> Ch 2: Parallel Validation (Apply) -> Ch 3: Combining Apply and Bind -> Ch 4: Inner Bind, Outer Apply -> Ch 5: Inner Apply, Outer Bind -> Ch 6: Contextual Validation

[Part 3] Completing Value Object Patterns Ch 1: SimpleValueObject -> Ch 2: ComparableSimpleValueObject -> Ch 3: ValueObject (Primitive) -> Ch 4: ComparableValueObject (Primitive) -> Ch 5: ValueObject (Composite) -> Ch 6: ComparableValueObject (Composite) -> Ch 7: TypeSafeEnum -> Ch 8: Architecture Tests -> Ch 9: UnionValueObject

[Part 4] Practical Guide Ch 1: Functorium Framework Integration -> Ch 2: ORM Integration Patterns -> Ch 3: CQRS and Value Objects -> Ch 4: Testing Strategies

[Part 5] Domain-Specific Practical Examples Ch 1: E-Commerce Domain -> Ch 2: Finance Domain -> Ch 3: User Management Domain -> Ch 4: Scheduling Domain


  • .NET 10.0 SDK or later
  • VS Code + C# Dev Kit extension
  • Basic knowledge of C# syntax

functional-valueobject/
├── Part0-Introduction/ # Part 0: Introduction
├── Part1-ValueObject-Concepts/ # Part 1: Understanding Value Object Concepts (16)
│ ├── 01-Basic-Divide/
│ ├── 02-Defensive-Programming/
│ ├── ...
│ └── 16-Architecture-Test/
├── Part2-Validation-Patterns/ # Part 2: Mastering Validation Patterns (6)
│ ├── 01-Bind-Sequential-Validation/
│ ├── 02-Apply-Parallel-Validation/
│ ├── ...
│ └── 06-Contextual-Validation/
├── Part3-ValueObject-Patterns/ # Part 3: Completing Value Object Patterns (9)
│ ├── 01-SimpleValueObject/
│ ├── 02-ComparableSimpleValueObject/
│ ├── ...
│ └── 09-UnionValueObject/
├── Part4-Practical-Guide/ # Part 4: Practical Guide (4)
│ ├── 01-Functorium-Framework/
│ ├── 02-ORM-Integration/
│ ├── 03-CQRS-Integration/
│ └── 04-Testing-Strategies/
├── Part5-Domain-Examples/ # Part 5: Domain-Specific Practical Examples (4)
│ ├── 01-Ecommerce-Domain/
│ ├── 02-Finance-Domain/
│ ├── 03-User-Management-Domain/
│ └── 04-Scheduling-Domain/
├── Appendix/ # Appendix
└── index.md # This document

All example projects in every Part include unit tests. Tests follow the Unit Testing Guide.

Terminal window
# Build the entire tutorial
dotnet build functional-valueobject.slnx
# Test the entire tutorial
dotnet test --solution functional-valueobject.slnx

Part 1: Understanding Value Object Concepts (16)

ChTest ProjectKey Test Content
1BasicDivide.Tests.UnitException vs domain type division
2DefensiveProgramming.Tests.UnitDefensive programming, precondition validation
3FunctionalResult.Tests.UnitFin, Validation result types
4AlwaysValid.Tests.UnitAlways-valid value object creation
5OperatorOverloading.Tests.UnitOperator overloading, type conversion
6LinqExpression.Tests.UnitLINQ expressions, functional composition
7ValueEquality.Tests.UnitValue equality, hash codes
8ValueComparability.Tests.UnitComparability, sorting
9CreateValidateSeparation.Tests.UnitSeparation of creation and validation
10ValidatedValueCreation.Tests.UnitValidated value creation pattern
11ValueObjectFramework.Tests.UnitFramework type verification
12TypeSafeEnums.Tests.UnitType-safe enumerations
13ErrorCode.Tests.UnitStructured error codes
14ErrorCodeFluent.Tests.UnitDomainError helpers
15ValidationFluent.Tests.UnitFluentValidation-based validation
16ArchitectureTest.Tests.UnitArchitecture rule verification

Part 2: Mastering Validation Patterns (6)

ChTest ProjectKey Test Content
1BindSequentialValidation.Tests.UnitBind sequential validation
2ApplyParallelValidation.Tests.UnitApply parallel validation
3ApplyBindCombinedValidation.Tests.UnitApply+Bind combined validation
4ApplyInternalBindValidation.Tests.UnitInner Bind, outer Apply
5BindInternalApplyValidation.Tests.UnitInner Apply, outer Bind
6ContextualValidation.Tests.UnitContextual validation

Part 3: Completing Value Object Patterns (8)

ChTest ProjectKey Test Content
1SimpleValueObject.Tests.UnitSimpleValueObject verification
2ComparableSimpleValueObject.Tests.UnitComparableSimpleValueObject verification
3ValueObjectPrimitive.Tests.UnitValueObject (Primitive) verification
4ComparableValueObjectPrimitive.Tests.UnitComparableValueObject (Primitive) verification
5ValueObjectComposite.Tests.UnitValueObject (Composite) verification
6ComparableValueObjectComposite.Tests.UnitComparableValueObject (Composite) verification
7TypeSafeEnum.Tests.UnitSmartEnum + IValueObject verification
9UnionValueObject.Tests.UnitUnionValueObject (Discriminated Union) verification

Part 4: Practical Guide (4)

ChTest ProjectKey Test Content
1FunctoriumFramework.Tests.UnitFunctorium framework integration
2OrmIntegration.Tests.UnitEF Core value object integration
3CqrsIntegration.Tests.UnitCQRS pattern value object usage
4TestingStrategies.Tests.UnitValue object testing strategies

Part 5: Domain-Specific Practical Examples (4)

ChTest ProjectKey Test Content
1EcommerceDomain.Tests.UnitMoney, ProductCode, Quantity, OrderStatus
2FinanceDomain.Tests.UnitAccountNumber, InterestRate, ExchangeRate
3UserManagementDomain.Tests.UnitEmail, Password, PhoneNumber
4SchedulingDomain.Tests.UnitDateRange, TimeSlot, Duration

Follows the T1_T2_T3 naming convention:

// Method_ExpectedResult_Scenario
[Fact]
public void Create_ReturnsSuccess_WhenValueIsValid()
{
// Arrange
var input = "user@example.com";
// Act
var actual = Email.Create(input);
// Assert
actual.IsSucc.ShouldBeTrue();
}

All example code for this tutorial can be found in the Functorium project:

  • Framework types: Src/Functorium/Domains/ValueObjects/
  • Tutorial projects: Docs.Site/src/content/docs/tutorials/functional-valueobject/

This tutorial was written based on real-world experience developing the value object framework in the Functorium project.