exploring c# dsls: linq, fluent interfaces and expression trees
TRANSCRIPT
Exploring C# DSLs: LINQ, Fluent Interfaces and Expression Trees
Rasmus Kromann-Larsen
Me
• Freelance .NET Developer
• Core Group Member– Copenhagen .NET User Group– Aarhus .NET User Group
• JetBrains Academy Expert
Agenda
• Domain Specific Languages
• Static Reflection
• Code
Domain Specific Languages
• Language targeted at a specific problem
• Goals– Expressiveness / Productivity– Declarative over Imperative– Communication
• External vs Internal
SELECT ID, LastNameFROM Employees e WHERE EXISTS (
SELECT * FROM Orders oWHERE e.ID = o.EmployeeID AND OrderDate = '9/5/11')
(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t] )+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?: \r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:( ?:\r\n)?[\t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-
... snip ...
"()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t]) *))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t]) +|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\ .(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z |(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:( ?:\r\n)?[ \t])*))*)?;\s*)
Talk Focus
• Internal C# DSLs– Less ramp-up– Automatic tooling support– Emergent in many new libraries
• Developer benefits > non-dev communication
[Subject("Making a customer preferred")]public class when_a_regular_customer_is_made_preferred{ static Customer _customer; Establish context = () => _customer = new Customer(); Because of = () => _customer.MakePreferred(); It should_mark_the_customer_as_preferred = () => _customer.IsPreferred.ShouldBeTrue();}
people.Where(x => x.Age < 50)
from x in peoplewhere x.Age < 50select x
LINQ
• Most(?) successful C# DSL
• Depending on C# 3.0 features– Anonymous Types– Extension Methods– Expression Trees
• Great DSL building blocks
LINQ
people.Where(x => x.Age < 50)
from x in peoplewhere x.Age < 50select x
Expression Trees
Expression Trees
• Extracting AST-like structure from lambda expressions
• Expression<TDelegate>
Static Reflection
• Statically typed reference to code element• No magic strings• Tool support / Refactorability
• typeof(Person).GetProperty(”Name”); vs• GetProperty<Person>(x => x.Name);
GetProperty<Person>(x => x.Name)
GetPropertyNamepublic string GetPropertyName(Expression body){ // Unwrap boxing if (body is UnaryExpression) { body = ((UnaryExpression) body).Operand; } var memberExpression = body as MemberExpression; if (memberExpression == null) { throw new Exception("Descriptive exception message."); } return memberExpression.Member.Name;}
GetProperty<Person>(x => x.Friend.Name)
Object Printing
Recap
• We use DSLs almost every day
• Expression Trees are not (that) dangerous
• It doesn’t have to be hard to write a DSL!
More Information?
• Domain Specific Languages by Martin Fowler
• Open Source Projects– Fubu– Most IoC containers– AutoMapper– AutoFixture– Fluent Nhibernate... and many more.
Questions?
Rasmus Kromann-Larsen
www.rasmuskl.dk