Using Extension Methods on a C# Interface to Enable DCI in Xamarin

Scala has several nice language features, including the elegant use of val for immutable variables and var for mutable, but the feature that I miss the most on a day-to-day basis is “traits.”

Traits allow you to implement one or more methods of an interface. The canonical use is to “mix-in” behavior while avoiding the “diamond-problem.”

DCI has the idea that Objects (domain-meaningful entities that correspond to user conceptions) adopt Roles, which are context-specific. Roles interact to produce value. So, for instance, when you’re transferring money at an ATM, you’re dealing with two accounts that are the same type of Object (Account), but which are in two different roles in the context of “Transfer Money”: a TransferSource and a TransferSink. And an Account in a TransferSource role has different behavior than an Account in a TransferSink role (e.g., TransferSource expects to withdraw(Money amount) while TransferSink expects to credit(Money amount)).

In C#, the way to specify that a class has a certain set of behaviors is to specify those behaviors in an interface and specify that the class implements them:

public class Account: TransferSource, TransferSink

And then, of course, you would implement the various methods of TransferSource and TransferSink within Account.

But the very essence of DCI is the premise that classic OOP type-systems don’t appropriately capture the relationships between Objects-in-Roles, even though “Objects-in-Roles working with each other” is the domain-users mental model (“I pick a source account, and a destination account, and specify an amount, and the amount is debited from the source and credited to the destination”). So DCI says that the TransferTo method that corresponds to the use-case should be elevated to a first-class object.

But in C# you cannot partially implement an interface. But you can create and implement an extension method on an interface!

  public static class TransferContextTrait
  {
    public static void TransferTo(this TransferSource self, TransferSink sink, Decimal amount)
    {
        try
        {
            if(self.Funds < amount)
            {
                self.FailTransfer(new TransferFailedReason("Insufficient Funds"));
            }
            else
            {
                self.Withdraw(amount);
                sink.Deposit(amount);

                var details = new TransferDetails(self.Name, sink.Name, amount);
                self.AccomplishTransfer(details);
            }
        }
        catch(Exception x)
        {
            self.FailTransfer(new TransferFailedReason(x.ToString()));
        }
    }
}

Note an interesting restriction, though: You cannot trigger an event from within an extension method! So in this case, although I would have preferred to propagate the results of the calculation by self.TransferAccomplished(this, details) I have to use a proxy function in Account:

public void AccomplishTransfer(TransferDetails details)
{
       TransferAccomplished(this, new TArgs&lt;TransferDetails>(details));
}

public event EventHandler&lt;TArgs &lt;TransferDetails>> TransferAccomplished = delegate {};

I’ll be talking more about DCI and other cross-platform architectural techniques at MonkeySpace in Chicago next week. Hope to see you there!

3 thoughts on “Using Extension Methods on a C# Interface to Enable DCI in Xamarin

  1. `But in C# you cannot partially implement an interface`
    But you can do it with `abstract` classes which are more resistance to change comparing to interfaces.

  2. Why is “resistance to change” a *benefit* in this situation?

    But even as an implementation technique, although `abstract` is initially appealing, it is insufficient for a few different reasons. For one thing, consider that we want `Account` to take on either of two roles: `TransferSource` and `TransferSink`. You would need to inherit through two abstract classes, whose inheritance relationship would be arbitrary (`abstract class TransferSource : TransferSink` or `abstract class TransferSink : TransferSource`)? Imagine how impractical that would be with many roles!

    Additionally, as you went further down the chain of abstract role-implementing classes, the `this` would provide unrestricted access to the `public` and `protected` methods of your higher-level role-implementing classes.

    Finally, although the use of an extension method on an interface is a little confusing on first encountered, I’d submit that it’s nowhere near as confusing as using inheritance to implement roles.

  3. Pingback: Xamarin Link Roundup – 28 July 2013 | Well Technically…

Comments are closed.