Freigeben über


Using C# properties to create a domain specific language

So this is nothing new really. People have been creating DSLs using methods and properties for quite some while now I think. But I recently used it to make my fakes (in the unit tests) easier to understand. And I think it turned out pretty neat. Here is an example of what a fake could look like:

    1:  public class FakeDatabaseWithOneUser : IMyDatabase
   2:  {
   3:      List<User> _users = new List<User>();
   4:      List<Address> _addresses = new List<Address>();
   5:      List<Invoice> _invoices = new List<Invoice>();
   6:   
   7:      public FakeDatabase()
   8:      {
   9:          _users.Add(new User("First", "Name"));
  10:   
  11:      public FakeDatabase AndTwoAddresses
  12:      {
  13:          get
  14:          {
  15:              _addresses.Add(new Address("Delivery Address"));
  16:              _addresses.Add(new Address("Invoice Address"));
  17:              return this;
  18:          }
  19:      }
  20:   
  21:      public FakeDatabase AndOneInvoice
  22:      {
  23:          get
  24:          {
  25:              _invoices.Add(new Invoice());
  26:              return this;
  27:          }
  28:      }
  29:   
  30:      // IMyDatabase implementation not shown here.
  31:  }

And using that fake a unit test could look something like this:

    1:      [TestMethod]
   2:      public void SelectedUserShouldListAllAddresses()
   3:      {
   4:          IMyDatabase db = new FakeDatabaseWithOneUser().AndTwoAddresses;
   5:          Assert.AreEqual(2, db.SelectUser(1).Address.Count);
   6:      }

But why do I use properties and not methods? I know there are people who think this use of properties violates the semantics of a property since the getter changes the state of the object. I don't agree. First of all these are not properties, these are part of my DSL. Second I think getting rid of the parenthesis (which would be there if these were methods instead) is nice and makes the code look better.

Comments

  • Anonymous
    February 10, 2010
    Interesting concept - I fall under the category of not liking "getters" that modify the object, but I see where you're coming from.  One other possibility that crossed my mind is something like the following, instead of method chaining: public FakeDatabase(params Action<FakeDatabase> actions) {  if (actions != null) {    foreach (var action in actions) {      action(this);    }  } } public static void AddInvoice(FakeDatabase fakeDb) {  fakeDb.Invoices.Add(new Invoice()); } Then the call would look something like: IMyDatabase db = new FakeDatabase(FakeDatabase.AddInvoice, FakeDatabase.AddTwoAddresses); It's not any better, but just a little different.  I probably wouldn't do that either, but rather make method calls one at a time. I do think that using C# (even if you're calling it something else) in an other-than-accepted manner is a little dangerous - in my opinion, if you expect your code to be maintained by others, you shouldn't expect them to know your personal coding quirks, especially as teams grow and developers become more and more generic.  And at the same time, if you get used to doing things using your own core style, other teams may not approve of this as you work with them, and then you'll end up having to get used to the "normal" way again, which may give you a disadvantage.

  • Anonymous
    February 10, 2010
    I also don't like getters that change the object as a general rule. And I would be much more hesitant to do this in "production" code because it definitly is other-than-expected. I think it is easier to accept for fakes used in the unit tests. It will always be a trade off between different things and you must make an informed decision.