Skip to content

in C# 3.5: interface + extension methods = mixin

On my current project, we have ended up with several classes that have the same, or nearly the same fields. The classes are generated from xsds that describe a set of SOAP services that we integrate with. We have tried avoiding the generation or tweaking the xsds to avoid the situation, but accepting the duplicate classes actually seemed to be the best way forward. So, we have code in a generated file like this:

namespace ServiceClients.Generated
{
	public partial class Address1
	{
		public string StreetNumber { get; set; }
		public string StreetName { get; set; }
		public string Suburb { get; set; }
		public string State { get; set; }
		public string PostCode { get; set; }
	}
 
	public partial class Address2
	{
		public string StreetNumber { get; set; }
		public string StreetName { get; set; }
		public string Suburb { get; set; }
		public string State { get; set; }
		public string PostCode { get; set; }
	}
}

Besides the obvious problem with duplication, this code is also difficult to extend. As just one example, we wanted to display addresses in a one-line format:

var address = new Address1
                  {
                      StreetNumber = "12A",
                      StreetName = "Spencer Street",
                      Suburb = "Melbourne",
                      State = "VIC",
                      PostCode = "3000",
                  };
Assert.AreEqual("12A Spencer Street, Melbourne, VIC 3000",
                address.ToOneLineFormat());

The implementation for this method is fairly simple, but where can we implement it so that we will only need to write it once? Ideally what we would like is a mixin: a way of adding new methods to a class without adding any fields, and without necessarily changing the type. Although C# does not have a language facility for mixins, we can get a similar effect by using an interface and an extension method.

namespace ServiceClients.Generated.Extensions
{
	public interface IAddress
	{
		string StreetNumber { get; }
		string StreetName { get; }
		string Suburb { get; }
		string State { get; }
		string PostCode { get; }
	}
 
	public static class AddressExtensions
	{
		public static string ToOneLineFormat(this IAddress address)
		{
			const string format = "{0} {1}, {2}, {3} {4}";
			return string.Format(format,
					address.StreetNumber,
					address.StreetName,
					address.Suburb,
					address.State,
					address.PostCode);
		}
	}
}

There is one more step. In C# the two concrete types need to explicitly implement the IAddress interface so that we can use the ToOneLineFormat method on them. I’ve never had much use for partial classes, but they were a lifesaver in this case. In another file away from the mammoth 40,000 line long svcutil generated file, the interface can be easily added to both classes.

namespace ServiceClients.Generated
{
	public partial class Address1 : IAddress {}
	public partial class Address2 : IAddress {}
}

And there it is: a mixin! The ToOneLineFormat method is defined in one place, can be used with either Address class, and there is no need to change the generated code or the inheritance hierarchy.

For a time I was quite sure I had heard that methods implemented directly on interfaces would be part of C# 4. I must have been delusional though, because it is not on the list of new features. If it were, it seems it would just be syntax sugar for the above approach.

Categories: c#, duplication, extension methods, mixin, partial classes, refactoring, svcutil.

Comment Feed

3 Responses

  1. Very nice! I like how simple that solution is. I am still scratching my head at classes that are almost exactly the same, but I really like your solution to the problem. What if the classes have slightly different method names though? Have you considering looking at an object mapper to solve that problem?

  2. The classes are generated by svcutil to deserialize xml documents that have similar or identical structures but live in different namespaces. svcutil can’t seem to handle this situation without generating multiple classes. Perhaps the same documents in different namespaces is the root of the problem, but that decision is outside of our control.

    If the classes had slightly different method names an object mapper might make good sense. We don’t have that problem though. A couple of teammates spiked out the use of AutoMapper. Looking at the spikes, we decided there was enough extra code being written for special cases that AutoMapper wasn’t of benefit.

    We’ve done some of our mapping in a similar way to the examples I showed above. I might write another post about it, as it is even more surprisingly elegant.

  3. Nice :)

    willemDecember 9, 2011 @ 20:18



Some HTML is OK

or, reply to this post via trackback.