I've decided working with enumerations beats working with generics. So now I've taken my little DSL experiment back to enumerations and started implementing the DateOfBirth DSL as a generic extension method.
Since the compiler infers the type based on the actual parameters used you don't need to supply the type when using the extensions methods. Very cool!
Now my DateOfBirthExtensions can work on anything that implements the IDateOfBirth interface, be it a person or an animal
namespace DSL{ class Program { static void Main(string[] args) { Person mark = Person.Named("Mark").BornOn(Day.theTwentyFifth).Of(Month.September).InTheYear(1972); Animal watson = Animal.Named("Watson").BornOn(Day.theSecond).Of(Month.January).InTheYear(2001).AndItIsA(Animal.KindOf.Dog); } }
public enum Day : int { theFirst = 1, theSecond = 2, theTwentyFifth = 25 }
public enum Month : int { January = 1, February = 2, September = 9 }
public interface IDateOfBirth { DateTime DateOfBirth { get; set; } }
public class Person : IDateOfBirth { public DateTime DateOfBirth { get; set; } public string Name { get; set; }
public static Person Named(string name) { Person p = new Person(name); return p; }
protected Person(string name) { Name = name; } }
public class Animal : IDateOfBirth { public enum KindOf { Dog, Cat }
public DateTime DateOfBirth { get; set; } public string Name { get; set; } public KindOf KindOfAnimal { get; set; }
public static Animal Named(string name) { Animal animal = new Animal(); animal.Name = name; return animal; } public Animal AndItIsA(KindOf kind) { KindOfAnimal = kind; return this; } }
public static class DateOfBirthExtensions { public static T BornOn<T>(this T p, Day day) where T : IDateOfBirth { p.DateOfBirth = new DateTime(p.DateOfBirth.Year, p.DateOfBirth.Month, (int)day); return p; }
public static T Of<T>(this T p, Month month) where T : IDateOfBirth { p.DateOfBirth = new DateTime(p.DateOfBirth.Year, (int)month, p.DateOfBirth.Day); return p; }
public static T InTheYear<T>(this T p, int year) where T : IDateOfBirth { p.DateOfBirth = new DateTime(year, p.DateOfBirth.Month, p.DateOfBirth.Day); return p; } }
}