C# Extension Methods Demystified
geekswithblogs.net
geekswithblogs.net
This is also another area where C# took a narrow view of language features and implemented the bare minimum needed to get LINQ working. Why not take a general view of type extensions, and support type extensions as a proper feature versus a hack for LINQ? That is, support all members, including static members, for type extensions.
Then C# 5.0 brought Async, a huge feature.
In terms of making the language more powerful I would call those on par with extending out extension methods.
* adding useful hacks to Apple classes:
UIView FindTitleView (this UINavigationBar bar)
string GetDeviceName (this UIDevice device)
* keeping formatting consistent across the app: string FormatViewCount (this Document doc)
string FormatCommentDate (this Comment comment)
* sometimes I really want to separate the class and some functions operating on its data, or providing useful helpers on top of this class: string SuggestTitle (this Document doc)
Uri [] GetResources (this Document doc)
Because they live in different namespaces, I only see UIKit and formatting extensions in UI code, data analysis in business layer, and so on.For example:
public static string AsString(this object me, string defaultValue = null)
public static int AsInt(this object me, int defaultValue = default(int))
public static float AsFloat(this object me, float defaultValue = default(float))
public static double AsDouble(this object me, double defaultValue = default(double))
public static Uri AsUri(this object me, Uri defaultValue = null)
public static bool AsBool(this object me, bool defaultValue = default(bool))
It's handy because you can do null checking in the extension method. Additionally, you can add some extra logic for converting specific runtime types. For example, calling .AsBool() on a string can check if the contents of the string is "1" or "true". public static int ToInt(this BaudRate baudRate)
{
switch (baudRate)
{
case BaudRate.BaudUnsupported:
return 0;
case BaudRate.Baud1200:
return 1200;
case BaudRate.Baud2400:
return 2400;
case BaudRate.Baud4800:
return 4800;
case BaudRate.Baud9600:
return 9600;
case BaudRate.Baud19200:
return 19200;
case BaudRate.Baud38400:
return 38400;
case BaudRate.Baud57600:
return 57600;
case BaudRate.Baud115200:
return 115200;
case BaudRate.Baud230400:
return 230400;
default:
throw new ArgumentOutOfRangeException("baudRate");
}
Not exactly the best example (and not necessarily the best way to do that), but it's a quick one. public enum AnchorFace
{
/// <summary>0</summary>
XLow,
/// <summary>1</summary>
XHigh,
/// <summary>2</summary>
YLow,
/// <summary>3</summary>
YHigh,
/// <summary>4</summary>
ZLow,
/// <summary>5</summary>
ZHigh
}
public static class AnchorFaceHelper
{
/// <summary>Normal Vector for the face</summary>
public static Vector3D GetNormalVector(this AnchorFace self)
{
switch (self)
{
case AnchorFace.ZLow:
return new Vector3D(0, 0, -1);
case AnchorFace.ZHigh:
return new Vector3D(0, 0, 1);
case AnchorFace.YLow:
return new Vector3D(0, -1, 0);
case AnchorFace.YHigh:
return new Vector3D(0, 1, 0);
case AnchorFace.XLow:
return new Vector3D(-1, 0, 0);
default: // XHigh
return new Vector3D(1, 0, 0);
}
}
}