Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
C# Extension Methods Demystified (geekswithblogs.net)
40 points by strangeloops on March 28, 2013 | hide | past | favorite | 16 comments


The C# (and presumably VB) compiler just looks for an attribute with the right namespace and name (System.Runtime.CompilerServices.ExtensionAttribute). If you're using .NET 2.0 you can get extension methods just by declaring you own attribute with that name and using it.

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.


I also prefer F#'s more general approach, which allows all kinds of extension members (static or instance, methods, properties, and events). But members of the C# team have repeatedly explained that they were the "long pole" during the LINQ work, so I think it's perfectly understandable that they took a more limited approach.


That explanation works for C# 3, but there have been two major releases since, which added relatively little to the language. They could have rounded out the LINQ-only stuff by now.


C# 4.0 brought support for Dynamic, a pretty damn big change. And of course optional and default parameters, another huge boon.

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.


And I think most of the compiler team has been busy with roslyn, which sounds like a pretty big rewrite.


I use extension methods in a MonoTouch app for different purposes.

* 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.


One of my favorite uses of extension methods is to have semi-intelligent type coercers/converters.

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".


One good use I have found for extension methods in C# is providing object.verb methods for enums.


I tend to write object.parse(byte[] buffer) methods a lot, especially when the object type itself is being defined in another team's code.


I tend to use them to extend IQueryable to provide "scopes" that I am familiar with from Rails.


Could you elaborate on that? An example?


    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);
            }
        }
    }


I'm not OP, but something like:

        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.


I'm sceptic to devs who don't treasure their own string, IEnumerable etc extensions ;)


My favourite is probably String.NotNullOrEmpty, I really hate to prepend ! to stuff.





Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: