Using extension methods to decrease the surface area of a C# interface
- by brian_ritchie
An interface defines a contract to be implemented by one or more classes. One of the keys to a well-designed interface is defining a very specific range of
functionality. The profile of the interface should be limited to a single purpose & should have the minimum methods required to implement this functionality. Keeping the interface tight will keep those implementing the interface from getting lazy & not implementing it properly. I've seen too many overly broad interfaces that aren't fully implemented by developers. Instead, they just throw a NotImplementedException for the method they didn't implement.
One way to help with this issue, is by using extension methods to move overloaded method definitions outside of the interface.
Consider the following example:
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, "Courier New", Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
1: public interface IFileTransfer
2: {
3: void SendFile(Stream stream, Uri destination);
4: }
5:
6: public static class IFileTransferExtension
7: {
8: public static void SendFile(this IFileTransfer transfer,
9: string Filename, Uri destination)
10: {
11: using (var fs = File.OpenRead(Filename))
12: {
13: transfer.SendFile(fs, destination);
14: }
15: }
16: }
17:
18: public static class TestIFileTransfer
19: {
20: static void Main()
21: {
22: IFileTransfer transfer = new FTPFileTransfer("user", "pass");
23: transfer.SendFile(filename, new Uri("ftp://ftp.test.com"));
24: }
25: }
In this example, you may have a number of overloads that uses different mechanisms for specifying the source file. The great part is, you don't need to implement these methods on each of your derived classes. This gives you a better interface and better code reuse.