PosInformatique.Foundations.People
1.1.0
Prefix Reserved
See the version list below for details.
dotnet add package PosInformatique.Foundations.People --version 1.1.0
NuGet\Install-Package PosInformatique.Foundations.People -Version 1.1.0
<PackageReference Include="PosInformatique.Foundations.People" Version="1.1.0" />
<PackageVersion Include="PosInformatique.Foundations.People" Version="1.1.0" />
<PackageReference Include="PosInformatique.Foundations.People" />
paket add PosInformatique.Foundations.People --version 1.1.0
#r "nuget: PosInformatique.Foundations.People, 1.1.0"
#:package PosInformatique.Foundations.People@1.1.0
#addin nuget:?package=PosInformatique.Foundations.People&version=1.1.0
#tool nuget:?package=PosInformatique.Foundations.People&version=1.1.0
PosInformatique.Foundations.People
Introduction
This package provides lightweight, strongly-typed value objects to standardize first names and last names across your applications:
FirstName: normalized, properly cased first names.LastName: normalized, fully uppercased last names.
It also includes:
IPerson: a small interface to represent nominative people with FirstName and LastName.- Extension methods on
IPersonfor consistent display/order names and initials. NameNormalizer: helper methods when you only have the separated first/last names.
Typical use cases: domain entities (User, Customer, Employee, Contact), consistent UI display (Blazor components, lists), alphabetical ordering (directories), and avatar initials.
Install
You can install the package from NuGet:
dotnet add package PosInformatique.Foundations.People
Features
- Strongly-typed FirstName and LastName with validation and normalization
- Business rules:
FirstName: title-cased words; letters only; separators: space, hyphenLastName: fully uppercased; letters only; separators: space, hyphen- No consecutive/trailing separators; max length 50
- Acts like read-only char arrays: indexer and Length
- Implements
IParsable<T>,IFormattable,IComparable<T>,IEquatable<T> - Implicit conversions to/from string
IPersoninterface for nominative person abstractionPersonExtensionsfor display name, ordering name, and initialsNameNormalizerutilities for first/last names withoutIPerson
Business rules
FirstName
- Max length: 50.
- Allowed characters: letters only; separators: ' ' and '-'.
- Normalization:
- Each word starts uppercase and continues lowercase (e.g., "John", "John Henri-Smith").
- No consecutive separators, ths trailing separators are removed.
LastName
- Max length: 50.
- Allowed characters: letters only; separators: ' ' and '-'.
- Normalization:
- Entire value uppercased (e.g., "DOE", "SMITH-JOHNSON").
- No consecutive separators, the trailing separators are removed.
FirstName examples
Create / implicit conversion
// Implicit conversion validates and normalizes:
FirstName firstName = "john henri-smith"; // -> "John Henri-Smith"
// Explicit create:
var firstName2 = FirstName.Create(" alice--marie "); // -> "Alice-Marie"
// IsValid
var ok = FirstName.IsValid("Élodie"); // true
var notOk = FirstName.IsValid("John_123"); // false
Parse / TryParse
// Parse (throws on invalid)
var firstName = FirstName.Parse("béAtrice", provider: null); // "Béatrice"
// TryParse (no exceptions)
if (FirstName.TryParse("jeAn - pierre", provider: null, out var firstName))
{
Console.WriteLine(firstName); // "Jean-Pierre"
}
Length and indexer
var firstName = FirstName.Create("Jean-Pierre");
var len = firstName.Length; // 11
var firstLetter = firstName[0]; // 'J'
var dash = firstName[4]; // '-'
// Enumerate characters
foreach (var c in firstName) { /* ... */ }
Comparisons and equality
var a = FirstName.Create("Alice");
var b = FirstName.Create("ALICE"); // normalized: "Alice"
Console.WriteLine(a == b); // true
Console.WriteLine(a != b); // false
Console.WriteLine(a <= b); // true
Console.WriteLine(a.CompareTo(b)); // 0
var list = new List<FirstName> { FirstName.Create("Zoé"), FirstName.Create("Ana") };
list.Sort(); // alphabetical by normalized value
LastName examples
Create / implicit conversion
LastName lastName = "dupond durand"; // -> "DUPOND DURAND"
var lastName2 = LastName.Create("le--gall"); // -> "LE GALL"
var ok = LastName.IsValid("O'Connor"); // false (apostrophe not allowed)
Parse / TryParse
var parsed = LastName.Parse("martin", provider: null); // "MARTIN"
if (LastName.TryParse("van - damme", provider: null, out var lastName))
{
Console.WriteLine(lastName); // "VAN DAMME"
}
Length and indexer
var lastName = LastName.Create("LE GALL");
var len = lastName.Length; // 7
var firstLetter = lastName[0]; // 'L'
var space = lastName[2]; // ' '
// Enumerate characters
foreach (var c in lastName) { /* ... */ }
Comparisons and equality
var a = LastName.Create("DURAND");
var b = LastName.Create("durand"); // normalized to "DURAND"
Console.WriteLine(a == b); // true
Console.WriteLine(a < LastName.Create("MARTIN")); // true
var list = new List<LastName> { LastName.Create("ZOLA"), LastName.Create("ABEL") };
list.Sort(); // alphabetical by normalized value
IPerson
IPerson represents a nominative person with a normalized FirstName and LastName. Implement this in domain types like User, Customer, Employee, Contact.
public sealed class User : IPerson
{
public User(FirstName firstName, LastName lastName)
{
FirstName = firstName;
LastName = lastName;
}
public FirstName FirstName { get; }
public LastName LastName { get; }
}
You can also accept string and normalize:
public sealed class Customer : IPerson
{
public Customer(string firstName, string lastName)
{
// Implicit conversions validate and normalize
FirstName = firstName;
LastName = lastName;
}
public FirstName FirstName { get; }
public LastName LastName { get; }
}
PersonExtensions
Utilities for consistent display, ordering, and initials on any IPerson.
GetFullNameForDisplay(): "First-Name LASTNAME" (e.g., "John DOE"). Use in UI display (e.g., Blazor component).GetFullNameForOrder(): "LASTNAME First-Name" (e.g., "DOE John"). Use for alphabetical directories by last name.GetInitials(): first letter of FirstName + first letter of LastName (e.g., "JD"). Use as fallback when avatar image is not available.
Examples:
var user = new User("jean-paul", "dupont");
var display = user.GetFullNameForDisplay(); // "Jean-Paul DUPONT"
var order = user.GetFullNameForOrder(); // "DUPONT Jean-Paul"
var initials = user.GetInitials(); // "JD"
Blazor example:
@code {
[Parameter] public IPerson Person { get; set; } = default!;
}
<h3>@Person.GetFullNameForDisplay()</h3>
<span class="avatar">@Person.GetInitials()</span>
Sorting by order name:
var people = new List<IPerson>
{
new User("alice", "martin"),
new User("bob", "durand"),
new User("Élodie", "zola")
};
var ordered = people
.OrderBy(p => p.GetFullNameForOrder(), StringComparer.Ordinal)
.ToList();
// "DURAND Bob", "MARTIN Alice", "ZOLA Élodie"
NameNormalizer
When you only have separate FirstName and LastName (not an IPerson), use NameNormalizer.
GetFullNameForDisplay(firstName, lastName)⇒ "First-Name LASTNAME"GetFullNameForOrder(firstName, lastName)⇒ "LASTNAME First-Name"
Examples:
var firstName = FirstName.Create("marie-claire");
var lastName = LastName.Create("le gall");
var display = NameNormalizer.GetFullNameForDisplay(firstName, lastName); // "Marie-Claire LE GALL"
var order = NameNormalizer.GetFullNameForOrder(firstName, lastName); // "LE GALL Marie-Claire"
Error handling tips
- Use
TryParse/TryCreatewhen you want to avoid exceptions:
if (FirstName.TryParse(inputFirstName, null, out var firstName) &&
LastName.TryParse(inputLastName, null, out var lastName))
{
var user = new User(firstName, lastName);
}
else
{
// handle invalid inputs
}
Links
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages (6)
Showing the top 5 NuGet packages that depend on PosInformatique.Foundations.People:
| Package | Downloads |
|---|---|
|
PosInformatique.Foundations.People.EntityFramework
Provides Entity Framework Core integration for the FirstName and LastName value objects from PosInformatique.Foundations.People. Offers fluent configuration helpers and converters to map normalized first and last names as NVARCHAR(50) columns with proper value conversion and comparison. |
|
|
PosInformatique.Foundations.People.FluentValidation
Provides FluentValidation extensions to validate first and last names using the strongly-typed FirstName and LastName value objects from PosInformatique.Foundations.People. |
|
|
PosInformatique.Foundations.People.FluentAssertions
Provides FluentAssertions extensions for FirstName and LastName value objects from PosInformatique.Foundations.People, resolving the Should() ambiguity and enabling idiomatic assertions like Should().Be(string) on normalized values. |
|
|
PosInformatique.Foundations.People.Json
Provides System.Text.Json converters for the FirstName and LastName value objects. Enables seamless serialization and deserialization of validated person names within JSON documents. |
|
|
PosInformatique.Foundations.People.DataAnnotations
Provides DataAnnotations attributes to validate first and last names using the strongly-typed FirstName and LastName value objects from PosInformatique.Foundations.People. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.2.0-rc.1 | 100 | 3/31/2026 |
| 1.1.0 | 236 | 3/30/2026 |
| 1.1.0-rc.3 | 86 | 3/27/2026 |
| 1.1.0-rc.2 | 84 | 1/26/2026 |
| 1.1.0-rc.1 | 101 | 1/23/2026 |
| 1.0.0 | 575 | 11/19/2025 |
| 1.0.0-rc.4 | 403 | 11/19/2025 |
| 1.0.0-rc.3 | 395 | 11/18/2025 |
| 1.0.0-rc.2 | 395 | 11/18/2025 |
| 1.0.0-rc.1 | 394 | 11/18/2025 |
1.0.0
- Initial release with strongly-typed FirstName, LastName value objects.
- Add IPerson interface + extension methods
- NameNormalizer to normalize the composed names first name / last name