Now, here is a very common scenario when porting .NET class libraries to PCL:
public class SomeClassToPort
{
public static byte[] SomeMethodToPort()
{
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write("Result: {0}, {1}", 10, "Hello");
// some more writer operations ...
writer.Close(); // Non-existent in PCL
stream.Close(); // Non-existent in PCL
return stream.ToArray();
}
}
Correct, the Close() method is not available for streams, readers or writers in Portable Class Libraries! Since the method in practice only executes Dispose(), the Close() method has been excluded from PCL. Trying to build this code yields the following error:
error CS1061: 'System.IO.MemoryStream' does not contain a definition for 'Close' and no extension method 'Close' accepting a first argument of type 'System.IO.MemoryStream' could be found (are you missing a using directive or an assembly reference?)
Dispose() is generally available in PCL, so one solution is to replace all Close() calls with Dispose(). For those wanting to avoid the hassle and maintenance issues of replacing (potentially numerous) Close() calls, there is however a workaround.
Enter Extension Methods!
Extension methods are a perfect fit for dealing with a scenario like the above. You can just add a static class with an arbitrary name to the PCL library, with code similar to this:
public static class CloseExtensions
{
public static void Close(this Stream stream)
{
stream.Dispose();
}
public static void Close(this TextWriter writer)
{
writer.Dispose();
}
}
Now, the compiler will "translate" stream.Close() into the call CloseExtensions.Close(stream) (analogously for the StreamWriter object) and the Portable Class Library can then build successfully. The extension methods perform practically the same operations as the Close() methods in the .NET Framework. Subsequent calls to Dispose() have no effect, so this implementation should be fail-safe.
There is also no risk of name clashes; even when the PCL library is used in a .NET application the original Close() methods and the corresponding extension methods have completely different signatures (they can just be expressed equivalently in the code).
The Close() methods are probably the most obvious examples where this extension method technique can be applied, but whenever a PCL profile is not including an instance method of one type, the same technique may be applied. Other examples from the top of my head are:
- several methods from the Type class which are not available for Windows 8 (f.k.a. Store or Metro apps); much of this functionality has been replaced by TypeInfo instance and extension methods,
- Stream.BeginRead, Stream.EndRead, Stream.BeginWrite and Stream.EndWrite; again not available for Windows 8 but can be simulated using extension methods.
No comments:
Post a Comment