In the first part of this article, we have seen the domain model and its usage for examination question paper as Level 0 in our step by step making of a DSL.
Level 1: Static Class and Method for Instantiation
Let us pick up the Exam
constructor.
var dotnetExam = new Exam(".NET Fundamentals", Level.Beginner);
In what way can we make this as domain-friendly.
- How the question preparer can know the first parameter is title of the exam, if he was provided with NotePad only? Forgot about API documentation et al. He is not a developer
- Is it ok to have "
var
" and "new
" keywords in this DSL?
To answer the first question, let us try to use C# "Named Argument" feature.
var dotExam = new Exam(title: ".NET Fundamentals", level: Level.Beginner);
Alternatively, when instantiating the Exam
class, we can use the C# object initializer feature, if your domain allows this. When I'm designing the domain model for exam, I put constraints that Title
and Level
properties should be specified during instantiation. After that, these are only "get
". And also, I hate to design domain objects with default constructor when business requires some constraints. For this case, if we relax this constraint, we can refactor the Exam
as:
public string Title { get; set; }
public Level Level { get; set; }
public List<Question> Questions { get; private set; }
public Exam()
{
Question.QNo = 1;
Questions = new List<Question>();
}
and the instantiation would be:
var dotnetExam = new Exam { Title = ".NET Fundamentals", Level = Level.Beginner };
If we relax the rule of Exam
object instantiation, we can use C# optional parameter in the constructor as:
public Exam(string title="Untitled", Level level = Level.Beginner)
{
Title = title;
Level = level;
Question.QNo = 1;
Questions = new List<Question>();
}
and the instantiation would be:
var dotnetExam = new Exam(title: ".NET Fundamentals");
Since, the one I'm preparing here is for beginners, I left the default option for Level.
We have almost answered the first question. However, how are we going to answer the second question. Avoid using "new
", "var
" C# keywords. A static
factory method would be the option for this. Where can we create that method? In the Exam
class itself or on a separate static
class. Exam.create(...)
wouldn't fit into the DSL. So, let us create a static
class ExamBuilder
.
public static class ExamBuilder
{
public static Exam exam(string title = "Untitled", Level level = Level.Beginner)
{
return new Exam() { Title = title, Level = level };
}
}
You may wonder why the method name violates the .NET method naming convention. Yes, I have violated it, after all, I'm going to create this DSL for a domain user, not for a .NET developer. Readability matters in DSL. See the usage of this:
var dotnetExam = ExamBuilder.exam(title: ".NET Fundamentals");
Still, "var" creates some noises in the DSL. But as of now, it is a required devil. Otherwise, how can we call Exam
's AddQuestion()
method.
But, why do we require intermediate variable "dotnetExam
" here, because as a DSL, the user will add questions immediately after the "exam()
" method. So, we can enforce:
ExamBuilder.exam(".NET Fundamentals").addQuestion(...);
But, how can we pass "question
" objects to its "AddOption
" method to add options and how can we create second, third, forth...n number of questions.
<a href="http://www.udooz.net/article/9-dsl/12-domain-specific-language-using-c-40-part-2.html" rel="tag" style="display:none">CodeProject</a>