Member-only story
Mixin Pattern in .NET C#: From Lisp flavors to extension members and source generators (2026)
Imagine developing the back office of an e-commerce site. Products, orders, coupons and assistance plans share some capabilities, but not the same ones. Products and orders must be auditable: who created and changed them, and when. Coupons must be soft-deletable, because a deleted coupon must still appear in the orders that used it. Products and blog posts must be taggable, and products versioned, because two operators editing the same price is a Monday morning classic. The first idea is the one we all learned at school: a base class.
// Naive approach - What NOT to do
public abstract class Entity { public Guid Id { get; init; } = Guid.NewGuid(); }
public abstract class AuditableEntity : Entity
{
public DateTimeOffset CreatedAt { get; set; }
public string? ModifiedBy { get; set; }
}
public abstract class SoftDeletableAuditableEntity : AuditableEntity
{
public bool IsDeleted { get; set; }
}
public abstract class TaggableSoftDeletableAuditableEntity : SoftDeletableAuditableEntity
{
public HashSet<string> Tags { get; } = [];
}
public class Product : TaggableSoftDeletableAuditableEntity { }
// And now?
// Coupon: soft-deletable and versioned, but neither auditable nor taggable
// AssistancePlan: auditable, but it already inherits from SubscriptionFour capabilities make sixteen combinations, and C# gives every class one single base class. The hierarchy no longer models the domain: it models the order in…











