typed? dynamic? both! cross-platform dsls in c#
TRANSCRIPT
![Page 1: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/1.jpg)
![Page 2: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/2.jpg)
![Page 3: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/3.jpg)
![Page 4: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/4.jpg)
![Page 5: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/5.jpg)
![Page 6: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/6.jpg)
-And look what you've done to mother! She's worn out fiddling with all your proxy classes. - There's nowt wrong wi' proxy classes, lad! I've generated more proxy classes than you've had hot dinners!
![Page 7: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/7.jpg)
![Page 8: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/8.jpg)
![Page 9: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/9.jpg)
dynamic client = WeirdWildStuffFactory.GiveMeOneOfThose();
client.NowICanPretendAnySillySentenceIsAMethodCall();client.AndICanSendAnyArguments(1, "2", new Stream[] {});
var result = client.MeaningOfLife * 42 * Guid.NewGuid();
Assert.AreEqual(42, result);
![Page 10: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/10.jpg)
// Without dynamic binding
((Excel.Range)excelApp.Cells[1,1]).Value2 = "Name";var range2008 = (Excel.Range)excelApp.Cells[1,1];
// With dynamic binding
excelApp.Cells[1,1].Value = "Name";var range2010 = excelApp.Cells[1,1];
![Page 11: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/11.jpg)
// With Entity Framework
public User FindUserByEmail(string email){
return _context.Users.Where(x => x.Email == email).FirstOrDefault();
}
// With Simple.Data
public User FindUserByEmail(string email){
return Database.Open().Users.FindAllByEmail(email).FirstOrDefault();
}
![Page 12: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/12.jpg)
Background
Given
Name Birth date Height
John 1940-10-09 1.80
Paul 1942-06-18 1.80
George 1943-02-25 1.77
Ringo 1940-07-07 1.68
[Given(@"the following users exist in the database:")]
public void GivenTheFollowingUsersExist(Table table)
{
IEnumerable<dynamic> users = table.CreateDynamicSet();
db.Users.Insert(users);}
![Page 13: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/13.jpg)
![Page 14: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/14.jpg)
• This talk is not about making a choice on your behalf
![Page 15: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/15.jpg)
• In fact, this talk is about leaving you multiple choices
![Page 16: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/16.jpg)
• Moreover, this talk is about giving you an opportunity to change your mind later with minimum effort
![Page 17: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/17.jpg)
• This talk is about creating libraries that would expose both typed and dynamic API – but not as two different APIs
![Page 18: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/18.jpg)
• We will show how to make a single API that can be called from either static typed or dynamic client
![Page 19: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/19.jpg)
• Our hybrid API will have hybrid packaging – it will disable dynamic support when installed on platforms that lack runtime method binding
![Page 20: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/20.jpg)
![Page 21: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/21.jpg)
dynamic results = db.Companies.FindAllByCountry("Norway").FirstOrDefault(); // EXCEPTION
![Page 22: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/22.jpg)
var result = db.Companies.Where(x => x.CompanyName == "DynamicSoft").Select( x =>
new{
c.CompanyName,c.YearEstablished
});
![Page 23: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/23.jpg)
var result = db.Companies.Where(x => x.CompanyName == "DynamicSoft").Select( x =>
new{
c.CompanyName,c.YearEstablished
});
var result = db.Companies.FindByCompanyName("DynamicSoft").SelectCompanyNameAndYearEstablished();
![Page 24: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/24.jpg)
var result = db.Companies.Where(x => x.CompanyName == "DynamicSoft").Select( x =>
new{
c.CompanyName,c.YearEstablished
});
dynamic x = new DynamicQueryExpression();var result = db.Companies
.Where(x.CompanyName == "DynamicSoft")
.Select(x.CompanyName, x.YearEstablished);
![Page 25: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/25.jpg)
• My API is my castle, any naming scheme is a matter of a personal preference
![Page 26: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/26.jpg)
• So we will leave method naming to personal opinion and ask a different question
![Page 27: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/27.jpg)
• Do you want to publish one API or two APIs?
![Page 28: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/28.jpg)
![Page 29: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/29.jpg)
interface IQueryBuilder{
From(...);Where(...);OrderBy(...);OrderByDescending(...);Select(...);
}
• This interface defines core operation set of our internal DSL and is shared by static typed and dynamic clients
• Typed and dynamic clients differ in what kind of arguments they send to the operations: static typed or dynamic respectively
![Page 30: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/30.jpg)
var result = db.Companies.Where(x => x.CompanyName > "D").OrderBy(x => x.CompanyName);
dynamic x = new DynamicQueryExpression();var result = db.Companies
.Where(x.CompanyName > "D")
.OrderBy(x.CompanyName);
• Exposing single API with two similar looking parameter syntax flavors unifies API operations across paradigms
• API users learn the same API operations no matter what paradigm they choose
• API users can switch paradigms at relatively low costs
![Page 31: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/31.jpg)
![Page 32: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/32.jpg)
LINQ expressions
custom expression
LINQ expressioncustom expression
custom expressioncustom expression
IDynamicMetaObjectProvider
![Page 33: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/33.jpg)
public class DynamicQueryExpression : QueryExpression, IDynamicMetaObjectProvider {
public DynamicQueryExpression() {}}
public interface IFinder{
Result Find<T>(Expression<Func<T>,bool>> query);Result Find(QueryExpression query);
}
public class QueryExpression{
// no public constructor}
Finder.Dynamic.dll
Finder.dll
![Page 34: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/34.jpg)
dynamic x = new DynamicQueryExpression();var finder = new Finder();var result = finder.Find(x.Companies).Where(
x.CompanyName.StartsWith("D") &&x.YearEstablished > 2000);
var finder = new Finder();var result = finder.Find<Companies>().Where(x =>
x.CompanyName.StartsWith("D") &&x.YearEstablished > 2000);
Dynamic client
Static typed client
![Page 35: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/35.jpg)
![Page 36: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/36.jpg)
![Page 37: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/37.jpg)
var result1 = from c in db.Companieswhere c.CompanyName.StartsWith("D")orderby c.CompanyNameselect new
{c.CompanyName,c.YearEstablished
};
var result2 = db.Companies.Where(x => x.CompanyName.StartsWith("D").OrderBy(x => x.CompanyName).Select( x =>
new{
c.CompanyName,c.YearEstablished
});
![Page 38: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/38.jpg)
interface ICommandBuilder{
From(...)Where(...)OrderBy(...)OrderByDescending(...)Select(...)
}
![Page 39: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/39.jpg)
interface ICommandBuilder{
ICommandBuilder From(string tableName);ICommandBuilder Where(string condition);ICommandBuilder OrderBy(params string[] columns);ICommandBuilder OrderByDescending(params string[] columns);ICommandBuilder Select(params string[] columns);
Command Build();}
// Usage example
var command = new CommandBuilder().From("Companies").Where("YearEstablished>2000 AND NumberOfEmployees<100").OrderBy("Country").Select("CompanyName", "Country", "City").Build();
![Page 40: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/40.jpg)
public class Command{
private string _table;private string _where;private List<string> _selectColumns;private List<KeyValuePair<string, bool>> _orderByColumns;
...}
![Page 41: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/41.jpg)
private string Format(){
var builder = new StringBuilder();
builder.AppendFormat("SELECT {0} FROM {1}",_selectColumns.Any() ? string.Join(",", _selectColumns) : "*", _table);
if (!string.IsNullOrEmpty(_where))builder.AppendFormat(" WHERE {0}", _where);
if (_orderByColumns.Any()) {builder.AppendFormat(" ORDER BY {0}",
string.Join(",", _orderByColumns.Select(x => x.Key + (x.Value ? " DESC" : string.Empty))));
}
return builder.ToString();}
![Page 42: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/42.jpg)
interface ICommandBuilder{
ICommandBuilder<T> From<T>();}
interface ICommandBuilder<T>{
ICommandBuilder<T> Where(Expression<Func<T, bool>> expression);
ICommandBuilder<T> OrderBy(Expression<Func<T, object>> expression);
ICommandBuilder<T> OrderByDescending(Expression<Func<T, object>> expression);
ICommandBuilder<T> Select(Expression<Func<T, object>> expression);
Command Build();}
![Page 43: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/43.jpg)
var command = new CommandBuilder().From<Companies>().Where(x =>
x.YearEstablished > 2000 &&x.NumberOfEmployees < 100)
.OrderBy(x =>x.Country)
.Select(x => new { x.CompanyName, x.Country, x.City })
.Build();
![Page 44: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/44.jpg)
![Page 45: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/45.jpg)
Nobody expects to parse LINQ expression trees!
![Page 46: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/46.jpg)
![Page 47: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/47.jpg)
var command = new CommandBuilder().From<Companies>().Where(x =>
x.YearEstablished > 2000 &&x.NumberOfEmployees < 100)
.OrderBy(x =>x.Country)
.Select(x => new { x.CompanyName, x.Country, x.City })
.Build();
![Page 48: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/48.jpg)
Expression<Func<Companies, bool>> expression = x => x.YearEstablished > 2000 && x.NumberOfEmployees < 100;
Lambda
AndAlso
GreaterThan
MemberAccess Constant
2000
Constant
100
MemberAccess
LessThan
Body
YearEstablished
NumberOfEmployees
Left Right
Left Right RightLeft
Member Value Member Value
Int32 Int32
![Page 49: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/49.jpg)
![Page 50: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/50.jpg)
![Page 51: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/51.jpg)
builder.From<Table>()
command.Where(x => expression<Func>T, bool>>
CommandExpression.FromLinqExpression(expression.Body)
builder.Build()
Assigns the type
Assigns Where expression
Converts tocustom expression
Evaluatesthe expression
![Page 52: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/52.jpg)
• Defined ICommandBuilder and ICommandBuilder<T> interfaces
• Implemented CommandBuilder
• Implemented CommandExpression• LINQ expression parsing
• Expression evaluation
![Page 53: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/53.jpg)
interface ICommandBuilder{
ICommandBuilder<T> From<T>();}
interface ICommandBuilder<T>{
ICommandBuilder<T> Where(Expression<Func<T, bool>> expression);
ICommandBuilder<T> OrderBy(Expression<Func<T, object>> expression);
ICommandBuilder<T> OrderByDescending(Expression<Func<T, object>> expression);
ICommandBuilder<T> Select(Expression<Func<T, object>> expression);
Command Build();}
![Page 54: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/54.jpg)
var result = db.From<Companies>().Where(x => x.CompanyName == "DynamicSoft").Select( x =>
new{
c.CompanyName,c.YearEstablished
});
dynamic x = new DynamicQueryExpression();var result = db.From(x.Companies)
.Where(x.CompanyName == "DynamicSoft")
.Select(x.CompanyName, x.YearEstablished);
![Page 55: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/55.jpg)
var result = db.From<Companies>().Where(x => x.CompanyName == "DynamicSoft").Select( x =>
new{
c.CompanyName,c.YearEstablished
});
dynamic x = new DynamicQueryExpression();var result = db.From(x.Companies)
.Where(x.CompanyName == "DynamicSoft")
.Select(x.CompanyName, x.YearEstablished);
![Page 56: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/56.jpg)
• Core API is static typed and packaged in assembly that doesn’t reference types from System.Dynamic namespace
• API exposes a DSL based on LINQ expressions
custom expression
LINQ expressioncustom expression
custom expressioncustom expression
IDynamicMetaObjectProvider
• Dynamic extensions for the API are packaged in a different assembly that is deployed on platforms with DLR support
![Page 57: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/57.jpg)
interface ICommandBuilder{
ICommandBuilder<T> From<T>();ICommandBuilder<object> From<T>(
CommandExpression expression);}
![Page 58: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/58.jpg)
interface ICommandBuilder<T>{
ICommandBuilder<T> Where(Expression<Func<T, bool>> expression);
ICommandBuilder<T> Where(CommandExpression expression);ICommandBuilder<T> OrderBy(
Expression<Func<T, object>> expression);ICommandBuilder<T> OrderBy(
params CommandExpression[] columns);ICommandBuilder<T> OrderByDescending(
Expression<Func<T, object>> expression);ICommandBuilder<T> OrderByDescending(
params CommandExpression[] columns);ICommandBuilder<T> Select(
Expression<Func<T, object>> expression);ICommandBuilder<T> Select(
params CommandExpression[] columns);Command Build();
}
![Page 59: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/59.jpg)
interface ICommandBuilder<T>{
...
ICommandBuilder<T> Where(Expression<Func<T, bool>> expression);
ICommandBuilder<T> Where(CommandExpression expression);
...}
// Typed clientbuilder.Where(x => x.CompanyName == "DynamicSoft");
// Dynamic clientx = new DynamicCommandExpression()builder.Where(x.DynamicName == "DynamicSoft");
![Page 60: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/60.jpg)
interface ICommandBuilder<T>{
...
ICommandBuilder<T> OrderBy(Expression<Func<T, object>> expression);
ICommandBuilder<T> OrderBy(params CommandExpression[] columns);
...}
// Typed clientbuilder.OrderBy(x => x.CompanyName);
// Dynamic clientx = new DynamicCommandExpression()builder.OrderBy(x.CompanyName);
![Page 61: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/61.jpg)
interface ICommandBuilder<T>{
...
ICommandBuilder<T> Select(Expression<Func<T, object>> expression);
ICommandBuilder<T> Select(params CommandExpression[] columns);
...}
// Typed clientbuilder.Select(x => new { x.Country, x.CompanyName });
// Dynamic clientx = new DynamicCommandExpression()builder.Select(x.Country, x.CompanyName);
![Page 62: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/62.jpg)
public ICommandBuilder<T> Where(Expression<Func<T, bool>> expression)
{_command.Where(
CommandExpression.FromLinqExpression(expression.Body));return this;
}
public ICommandBuilder<T> Where(CommandExpression expression)
{_command.Where(expression);return this;
}
![Page 63: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/63.jpg)
DynamicObject
CommandExpression
IDynamicMetaObjectProviderCommandExpression
DynamicCommandExpression
DynamicMetaObject
• DynamicMetaObject
![Page 64: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/64.jpg)
![Page 65: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/65.jpg)
Where(dynamic expression)
Where(CommandExpression)
DynamicCommandExpressionto CommandExpression
builder.Where(expression).Build()
Call with dynamicargument
Finds suitablemethod overload
Converts totyped expression
Follow typedbuilder workflow
![Page 66: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/66.jpg)
input
return
CommandProcessor
![Page 67: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/67.jpg)
// Typed
var command = commandBuilder.From<Companies>().Build();
var commandProcessor = new CommandProcessor(command);var result = commandProcessor.FindOne<Companies>();
// Dynamic
var x = new DynamicCommandExpression();var command = commandBuilder
.From(x.Companies)
.Build();var commandProcessor = new CommandProcessor(command);var row = commandProcessor.FindOne(x.Companies);
![Page 68: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/68.jpg)
public interface ICommandProcessor{
T FindOne<T>();IEnumerable<T> FindAll<T>();
}
public abstract class CommandProcessor : ICommandProcessor{
protected readonly Command _command;
protected CommandProcessor(Command command){
_command = command;}
...
protected abstract IEnumerable<IDictionary<string, object>> Execute();
}
![Page 69: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/69.jpg)
IDictionary string object
objectIDictionary string object
IEnumerable IDictionary string object
objectIEnumerable IDictionary string object
![Page 70: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/70.jpg)
dynamic x = new DynamicCommandExpression();var command = SelectAllCommand();var commandProcessor = new FakeCommandProcessor(command);
// Single row
var result = commandProcessor.FindOne();Assert.AreEqual("DynamicSoft", result["CompanyName"]);
// Collection
var result = commandProcessor.FindAll();Assert.AreEqual(2, result.Count());Assert.AreEqual("DynamicSoft", result.First()["CompanyName"]);Assert.AreEqual("StaticSoft", result.Last()["CompanyName"]);
![Page 71: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/71.jpg)
public interface ICommandProcessor{
T FindOne<T>() where T : class;ResultRow FindOne();ResultRow FindOne(CommandExpression expression);IEnumerable<T> FindAll<T>() where T : class;IEnumerable<ResultRow> FindAll();ResultCollection FindAll(CommandExpression expression);
}
![Page 72: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/72.jpg)
public class DynamicResultRow : ResultRow, IDynamicMetaObjectProvider
{internal DynamicResultRow(IDictionary<string, object> data)
: base(data){}...
}
public class DynamicResultCollection : ResultCollection, IDynamicMetaObjectProvider
{internal DynamicResultCollection(IEnumerable<ResultRow> data)
: base(data){}...
}
![Page 73: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/73.jpg)
dynamic x = new DynamicCommandExpression();var command = SelectAllCommand();var commandProcessor = new FakeCommandProcessor(command);
// Dynamic result// Requires BindGetMember overloadvar result = commandProcessor.FindOne();Assert.AreEqual("DynamicSoft", result.CompanyName);
// Typed result// Requires BindConvert overloadCompanies result = commandProcessor.FindOne();Assert.AreEqual("DynamicSoft", result.CompanyName);
![Page 74: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/74.jpg)
![Page 75: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/75.jpg)
processor.FindAll<T>(x => expression<T>)
processor.Execute()
IEnumerable<IDictionary<string, object>>
ToObject<T>()
Call to a genericmethod overload
Executes SQL command
Returns nativeresult
Converts resultsto typed objects
![Page 76: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/76.jpg)
processor.FindAll(dynamic)
processor.Execute()
ToObject<DynamicResultCollection>()
IEnumerable<T> results
Call to a non-genericmethod overload
Follows typedexecution path
Converts resultsto typed objects
Converts resultsto typed objects
![Page 77: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/77.jpg)
![Page 78: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/78.jpg)
![Page 79: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/79.jpg)
![Page 80: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/80.jpg)
![Page 81: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/81.jpg)
MAKEHYBRID
APINOT
HYBRID WAR
![Page 82: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/82.jpg)
![Page 83: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/83.jpg)
![Page 84: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/84.jpg)
![Page 85: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/85.jpg)
![Page 86: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/86.jpg)
![Page 87: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/87.jpg)
LINQ expressions
custom expression
LINQ expressioncustom expression
custom expressioncustom expression
IDynamicMetaObjectProvider
![Page 88: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/88.jpg)
![Page 89: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/89.jpg)
![Page 90: Typed? Dynamic? Both! Cross-platform DSLs in C#](https://reader030.vdocuments.site/reader030/viewer/2022032419/55a2bd561a28ab6f268b45af/html5/thumbnails/90.jpg)