Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Domain Specific Language using C# 4.0 - Part 2

4.00/5 (1 vote)
26 Dec 2010CC (ASA 2.5)2 min read 11.5K  
Domain Specific Language using C# 4.0 - Part 2

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.

C#
var dotnetExam = new Exam(".NET Fundamentals", Level.Beginner); 

In what way can we make this as domain-friendly.

  1. 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
  2. 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.

C#
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:
C#
//Exam.cs
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:

C#
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:

C#
//Exam.cs
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:
C#
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.

C#
//ExamBuilder.cs
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:

C#
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:

C#
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>

License

This article, along with any associated source code and files, is licensed under The Creative Commons Attribution-ShareAlike 2.5 License