views:

2828

answers:

38

I'm starting to really love extension methods... I was wondering if anyone her has stumbled upon one that really blew their mind, or just found clever.

An example I wrote today:

Edited due to other users' comments:

public static IEnumerable<int> To(this int fromNumber, int toNumber) {
    while (fromNumber < toNumber) {
        yield return fromNumber;
        fromNumber++;
    }
}

This allows a for loop to be written as a foreach loop:

foreach (int x in 0.To(16)) {
    Console.WriteLine(Math.Pow(2, x).ToString());
}

I can't wait to see other examples! Enjoy!

+1  A: 

I like this one. It is a variation on the String.Split method that allows the use of an escape character to suppress splitting when the split character is intended to be in the actual string.

Robert Harvey
+12  A: 

The full solution is too large to put here, but I wrote a series of extension methods that would allow you to easily convert a DataTable into a CSV.

public static String ToCSV(this DataTable dataTable)
{
    return dataTable.ToCSV(null, COMMA, true);
}  

public static String ToCSV(this DataTable dataTable, String qualifier)
{
    return dataTable.ToCSV(qualifier, COMMA, true);
}

private static String ToCSV(this DataTable dataTable, String qualifier, String delimiter, Boolean includeColumnNames)
{
    if (dataTable == null) return null;

    if (qualifier == delimiter)
    {
     throw new InvalidOperationException(
      "The qualifier and the delimiter are identical. This will cause the CSV to have collisions that might result in data being parsed incorrectly by another program.");
    }

    var sbCSV = new StringBuilder();

    var delimiterToUse = delimiter ?? COMMA;

    if (includeColumnNames) 
     sbCSV.AppendLine(dataTable.Columns.GetHeaderLine(qualifier, delimiterToUse));

    foreach (DataRow row in dataTable.Rows)
    {
     sbCSV.AppendLine(row.ToCSVLine(qualifier, delimiterToUse));
    }

    return sbCSV.Length > 0 ? sbCSV.ToString() : null;
}

private static String ToCSVLine(this DataRow dataRow, String qualifier, String delimiter)
{
    var colCount = dataRow.Table.Columns.Count;
    var rowValues = new String[colCount];

    for (var i = 0; i < colCount; i++)
    {
     rowValues[i] = dataRow[i].Qualify(qualifier);
    }

    return String.Join(delimiter, rowValues);
}

private static String GetHeaderLine(this DataColumnCollection columns, String qualifier, String delimiter)
{
    var colCount = columns.Count;
    var colNames = new String[colCount];

    for (var i = 0; i < colCount; i++)
    {
     colNames[i] = columns[i].ColumnName.Qualify(qualifier);
    }

    return String.Join(delimiter, colNames);
}

private static String Qualify(this Object target, String qualifier)
{
    return qualifier + target + qualifier;
}

At the end of the day, you could call it like this:

someDataTable.ToCSV(); //Plain old CSV
someDataTable.ToCSV("\""); //Double quote qualifier
someDataTable.ToCSV("\"", "\t"); //Tab delimited
Josh
I actually wrote a whole other set of extension methods as overloads that will allow you to pass in a custom class that defines things like formatting, column names, etc... It was simply too much to include in this post.
Josh
+10  A: 

Well this isn't exactly clever but I've modified the ----OrDefault methods so you could specify a default item inline instead of checking for null later in your code:

    public static T SingleOrDefault<T> ( this IEnumerable<T> source, 
                                    Func<T, bool> action, T theDefault )
    {
        T item = source.SingleOrDefault<T>(action);

        if (item != null)
            return item;

        return theDefault;
    }

Its incredible simple but really helps clean up those null checks. Best used when your UI is expecting a list of X items, like a tournament system, or game player slots and you want to display "empty seats".

Usage:

    return jediList.SingleOrDefault( 
                 j => j.LightsaberColor == "Orange", 
               new Jedi() { LightsaberColor = "Orange", Name = "DarthNobody");
jfar
Nice, I was always wondering why the did not include that overload for SingleOrDefault and FirstOrDefault, good initiative on adding it!
rmoore
I made something similar, although I used a Func<T> instead of T as the default.
Svish
Note that this won't work correctly for non-nullable types. The built-in SingleOrDefault extensions return default(T) when no item is found, and this will only be null for reference types or nullable value types.
LukeH
For example, your method will always return 0 when T is int and no matching item is found, regardless of the value of "theDefault" parameter.
LukeH
@Svish, yeah I have that signature written up too, I just posted this one because its easier to understand @Luke, yes I realize this but I've only used it so far for domain object collections.
jfar
personally I think it's not much cleaner than .SingleOrDefault()??new Foo()
Johannes Rudolph
+8  A: 

Here's one I hacked together, so feel free to pick holes in it. It takes an (ordered) list of integers and returns a list of strings of contiguous ranges. eg:

1,2,3,7,10,11,12  -->  "1-3","7","10-12"

The function (within a static class):

public static IEnumerable<string> IntRanges(this IEnumerable<int> numbers)
{
    int rangeStart = 0;
    int previous = 0;

    if (!numbers.Any())
        yield break;

    rangeStart = previous = numbers.FirstOrDefault();

    foreach (int n in numbers.Skip(1))
    {
        if (n - previous > 1) // sequence break - yield a sequence
        {
            if (previous > rangeStart)
            {
                yield return string.Format("{0}-{1}", rangeStart, previous);
            }
            else
            {
                yield return rangeStart.ToString();
            }
            rangeStart = n;
        }
        previous = n;
    }

    if (previous > rangeStart)
    {
        yield return string.Format("{0}-{1}", rangeStart, previous);
    }
    else
    {
        yield return rangeStart.ToString();
    }
}

Usage example:

this.WeekDescription = string.Join(",", from.WeekPattern.WeekPatternToInts().IntRanges().ToArray());

This code is used to convert data from a DailyWTF-worthy timetabling application. WeekPattern is a bitmask stored in a string "0011011100...". WeekPatternToInts() converts that to an IEnumerable<int>, in this case [3,4,6,7,8], which becomes "3-4,6-8". It provides the user with a compact description of the academic week ranges that a lecture occurs on.

geofftnz
I can't think of an immediate use for this, but it is awesome nonetheless :)
Josh
Thanks! I've added an example showing how I use it.
geofftnz
Why do unnecessary actions like unnecessary assigning previous = n, checking for first at the every iteration and formatting single number?
Dmitriy Matveev
My bad coding...
geofftnz
Fixed the things Dmitriy pointed out (thanks!)
geofftnz
Do you have one for the reverse as well?
Svish
@Svish: No I dont sorry, this was for display purposes only. If I've got a free moment I'll give it a go.
geofftnz
+10  A: 

Two that I like to use are the InserWhere<T> and RemoveWhere<T> Extension Methods that I've written. Working with ObservableCollections in WPF and Silverlight I often need to modify ordered lists without recreating them. These methods allow me to insert and remove according to a supplied Func, so .OrderBy() doesn't need to be re-called.

    /// <summary>
    /// Removes all items from the provided <paramref name="list"/> that match the<paramref name="predicate"/> expression.
    /// </summary>
    /// <typeparam name="T">The class type of the list items.</typeparam>
    /// <param name="list">The list to remove items from.</param>
    /// <param name="predicate">The predicate expression to test against.</param>
    public static void RemoveWhere<T>(this IList<T> list, Func<T, bool> predicate)
    {
        T[] copy = new T[] { };
        Array.Resize(ref copy, list.Count);
        list.CopyTo(copy, 0);

        for (int i = copy.Length - 1; i >= 0; i--)
        {
            if (predicate(copy[i]))
            {
                list.RemoveAt(i);
            }
        }
    }

    /// <summary>
    /// Inserts an Item into a list at the first place that the <paramref name="predicate"/> expression fails.  If it is true in all cases, then the item is appended to the end of the list.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list"></param>
    /// <param name="obj"></param>
    /// <param name="predicate">The sepcified function that determines when the <paramref name="obj"/> should be added. </param>
    public static void InsertWhere<T>(this IList<T> list, T obj, Func<T, bool> predicate)
    {
        for (int i = 0; i < list.Count; i++)
        { 
            // When the fuction first fails it inserts the obj paramiter. 
            // For example, in a list myList of ordered Int32's {1,2,3,4,5,10,12}
            // Calling myList.InsertWhere( 8, x => 8 > x) inserts 8 once the list item becomes greater then or equal to it.
            if(!predicate(list[i]))
            {
                list.Insert(i, obj);
                return;
            }
        }

        list.Add(obj);
    }

Edit:
Talljoe made some significant improvements to the RemoveWhere/RemoveAll, that I had hastily constructed. With ~3mill items removing every third one the new version takes only ~50 milliseconds (less then 10 if it can call List.RemoveAll !) as opposed to the RemoveWhere 's multiple seconds (I got tired of waiting for it.)

Here is his greatly improved version, thanks again!

    public static void RemoveAll<T>(this IList<T> instance, Predicate<T> predicate)
    {
        if (instance == null)
            throw new ArgumentNullException("instance");
        if (predicate == null)
            throw new ArgumentNullException("predicate");
        if (instance is T[])
            throw new NotSupportedException();

        var list = instance as List<T>;
        if (list != null)
        {
            list.RemoveAll(predicate);
            return;
        }

        int writeIndex = 0;
        for (int readIndex = 0; readIndex < instance.Count; readIndex++)
        {
            var item = instance[readIndex];
            if (predicate(item)) continue;

            if (readIndex != writeIndex)
            {
                instance[writeIndex] = item;
            }
            ++writeIndex;
        }

        if (writeIndex != instance.Count)
        {
            for (int deleteIndex = instance.Count - 1; deleteIndex >= writeIndex; --deleteIndex)
            {
                instance.RemoveAt(deleteIndex);
            }
        }
    }
rmoore
RemoveWhere is somewhat inefficient due to all the memory shifting when you remove an item (unless the IList is a LinkedList). I've created a modified verion here: http://pastebin.com/f20e73b4e Differences: 1) Renamed to "RemoveAll" to match List<T>'s version. 2) Call List<T>'s version if applicable (more efficient than even my version 3) Use two indexes to walk to list and do an in-place overwrite of the values. 4) Handle case when someone passes an Array (I think I actually prefer throwing the exception, but I'd want to do it before modifying the array -- exercise for the reader).
Talljoe
I never even noticed the List<T>.RemoveAll, I simply assumed all of the extensions were extending IList<T>, which doesn't have it. Thank you for pointing it out! Sadly I can't make use of it, since ObservableCollection just inherits from IList. One thing of note, your check for point #2 will cause a stack overflow, Func<T, bool> to Predicate<T> can't be converted to Predicate. The second half of yours is significantly faster then mine though, I'm definitely going to implement that. If you don't mind I'll edit my post with the updated version.
rmoore
Go right ahead. Interesting about that infinite recursion, I was pretty sure I tested it and it worked. *shrug* This will make it work: list.RemoveAll(t => predicate(t));
Talljoe
A: 

Here's one I wrote recently at work and blogged about:

http://crazorsharp.blogspot.com/2009/03/cool-ienumberable-extension-method_25.html

It's basically IEnumerable.ToHtmlTable();

BFree
-1 for the XSS vulnerability.
finnw
Care to elaborate?
BFree
+1  A: 

Extension method on int to decode a bitmask specifying days (with first day of week being Monday in this case) to an enumeration of DayOfWeek enums:

public static IEnumerable<DayOfWeek> Days(this int dayMask)
{
    if ((dayMask & 1) > 0) yield return DayOfWeek.Monday;
    if ((dayMask & 2) > 0) yield return DayOfWeek.Tuesday;
    if ((dayMask & 4) > 0) yield return DayOfWeek.Wednesday;
    if ((dayMask & 8) > 0) yield return DayOfWeek.Thursday;
    if ((dayMask & 16) > 0) yield return DayOfWeek.Friday;
    if ((dayMask & 32) > 0) yield return DayOfWeek.Saturday;
    if ((dayMask & 64) > 0) yield return DayOfWeek.Sunday;
}
geofftnz
why do you use yield here? I'm curious how this works... If you have Monday and Friday, i.e. 0010001 as your dayMask, what will be the effect of using yield return versus return?
Jeff Meatball Yang
ah - I see - it basically starts where it left off in the bit mask as you iterate over it. Got it.
Jeff Meatball Yang
+5  A: 

A pair of extension methods to convert base-36 strings(!) to integers:

public static int ToBase10(this string base36)
{
    if (string.IsNullOrEmpty(base36))
        return 0;
    int value = 0;
    foreach (var c in base36.Trim())
    {
        value = value * 36 + c.ToBase10();
    }
    return value;
}

public static int ToBase10(this char c)
{
    if (c >= '0' && c <= '9')
        return c - '0';
    c = char.ToUpper(c);
    if (c >= 'A' && c <= 'Z')
        return c - 'A' + 10;
    return 0;
}

(Some genius decided that the best way to store numbers in the database was to encode them to strings. Decimals take too much space. Hex is better, but doesnt use the characters G-Z. So obviously you extend base-16 to base-36!)

geofftnz
After reading all these examples I think you should quit your job ;)
Josh
rmoore
+1 for sheer insanity
Kirschstein
I've used base 36 numbers, but only when I needed to support a big address space of human-readable identifiers that needed to fit into a 4-byte field in an ancient (and unmodifiable) system's message format. I still think that's a defensible use case, though the real solution was to throw away the ancient system.
Robert Rossney
There's always base64 :) I'm not sure what the decision-making process was in the app I was dealing with. I was told that the app actually uses flat-files for storing data and that to make it a multi-user system they just blast everything to a database on save and refresh local file storage on init.
geofftnz
+9  A: 

I have various .Debugify extension methods that are useful for dumping objects to a log file. For example, here's my Dictionary debugify (I have these for List, Datatable, param array, etc.):

public static string Debugify<TKey, TValue>(this Dictionary<TKey, TValue> dictionary) {
    string Result = "";

    if (dictionary.Count > 0) {
        StringBuilder ResultBuilder = new StringBuilder();

        int Counter = 0;
        foreach (KeyValuePair<TKey, TValue> Entry in dictionary) {
            Counter++;
            ResultBuilder.AppendFormat("{0}: {1}, ", Entry.Key, Entry.Value);
            if (Counter % 10 == 0) ResultBuilder.AppendLine();
        }
        Result = ResultBuilder.ToString();
    }
    return Result;
}

And here's one for a DbParameterCollection (useful for dumping database calls to the log file):

public static string Debugify(this DbParameterCollection parameters) {
    List<string> ParameterValuesList = new List<string>();

    foreach (DbParameter Parameter in parameters) {
        string ParameterName, ParameterValue;
        ParameterName = Parameter.ParameterName;

        if (Parameter.Direction == ParameterDirection.ReturnValue)
            continue;

        if (Parameter.Value == null || Parameter.Value.Equals(DBNull.Value))
            ParameterValue = "NULL";
        else
        {
            switch (Parameter.DbType)
            {
                case DbType.String:
                case DbType.Date:
                case DbType.DateTime:
                case DbType.Guid:
                case DbType.Xml:
                    ParameterValue
                        = "'" + Parameter
                                .Value
                                .ToString()
                                .Replace(Environment.NewLine, "")
                                .Left(80, "...") + "'"; // Left... is another nice one
                    break;

                default:
                    ParameterValue = Parameter.Value.ToString();
                    break;
            }

            if (Parameter.Direction != ParameterDirection.Input)
                ParameterValue += " " + Parameter.Direction.ToString();
        }

        ParameterValuesList.Add(string.Format("{0}={1}", ParameterName, ParameterValue));
    }

    return string.Join(", ", ParameterValuesList.ToArray());
}

Example result:

Log.DebugFormat("EXEC {0} {1}", procName, params.Debugify);
// EXEC spProcedure @intID=5, @nvName='Michael Haren', @intRefID=11 OUTPUT

Note that if you call this after your DB calls, you'll get the output parameters filled in, too. I call this on a line that includes the SP name so I can copy/paste the call into SSMS for debugging.


These make my log files pretty and easy to generate without interrupting my code.

Michael Haren
+1  A: 

This one creates array with single element added at the very beginning:

public static T[] Prepend<T>(this T[] array, T item)
{
    T[] result = new T[array.Length + 1];
    result[0] = item;
    Array.Copy(array, 0, result, 1, array.Length);
    return result;
}

string[] some = new string[] { "foo", "bar" };
...
some = some.Prepend("baz");

And this one helps me when I need to convert some expression to it's square:

public static double Sq(this double arg)
{
    return arg * arg;
}

(x - x0).Sq() + (y - y0).Sq() + (z - z0).Sq()
Dmitriy Matveev
Yikes! Prepend on an array is *such* a bad idea, conceptually. Be very sure you want/need this... Making it an extension method makes it very easy to fall into the trap of filling a large array by prepending a large set of values to an initially empty (or small) array, making a fresh temporary copy of each intermediate array in the process! Personally I wouldn't do it. (Same goes for an array Append, if you have that.)
peSHIr
I'm sure I need this. This is used by code where arrays is used widely and their modification is happening rarely.
Dmitriy Matveev
I agree that this is something you should generally use with caution. Perhaps you could include an overload that accepts multiple items to prepend, to avoid calling your method in loops.
Drew Noakes
If you must work with arrays, manipulators like this would be helpful. If you have coworkers who might use it wrong you could give it a name more indicative of its shortcomings like 'PrependSlow' or 'PrependAndCopy'. I like it +1
Michael Haren
+1  A: 

Here's another one I wrote:

    public static class StringExtensions
    {
        /// <summary>
        /// Returns a Subset string starting at the specified start index and ending and the specified end
        /// index.
        /// </summary>
        /// <param name="s">The string to retrieve the subset from.</param>
        /// <param name="startIndex">The specified start index for the subset.</param>
        /// <param name="endIndex">The specified end index for the subset.</param>
        /// <returns>A Subset string starting at the specified start index and ending and the specified end
        /// index.</returns>
        public static string Subsetstring(this string s, int startIndex, int endIndex)
        {
            if (startIndex < 0) throw new ArgumentOutOfRangeException("startIndex", "Must be positive.");
            if (endIndex < 0) throw new ArgumentOutOfRangeException("endIndex", "Must be positive.");
            if (startIndex > endIndex) throw new ArgumentOutOfRangeException("endIndex", "Must be >= startIndex.");
            return s.Substring(startIndex, (endIndex - startIndex));
        }

        /// <summary>
        /// Finds the specified Start Text and the End Text in this string instance, and returns a string
        /// containing all the text starting from startText, to the begining of endText. (endText is not
        /// included.)
        /// </summary>
        /// <param name="s">The string to retrieve the subset from.</param>
        /// <param name="startText">The Start Text to begin the Subset from.</param>
        /// <param name="endText">The End Text to where the Subset goes to.</param>
        /// <param name="ignoreCase">Whether or not to ignore case when comparing startText/endText to the string.</param>
        /// <returns>A string containing all the text starting from startText, to the begining of endText.</returns>
        public static string Subsetstring(this string s, string startText, string endText, bool ignoreCase)
        {
            if (string.IsNullOrEmpty(startText)) throw new ArgumentNullException("startText", "Must be filled.");
            if (string.IsNullOrEmpty(endText)) throw new ArgumentNullException("endText", "Must be filled.");
            string temp = s;
            if (ignoreCase)
            {
                temp = s.ToUpperInvariant();
                startText = startText.ToUpperInvariant();
                endText = endText.ToUpperInvariant();
            }
            int start = temp.IndexOf(startText);
            int end = temp.IndexOf(endText, start);
            return Subsetstring(s, start, end);
        }
    }

The motivation behind this one was simple. It always bugged me how the built in Substring method took startindex and length as it's parameters. It's ALWAYS much more helpful to do startindex and endindex. So, I rolled my own:

Usage:

        string s = "This is a tester for my cool extension method!!";
        s = s.Subsetstring("tester", "cool",true);

The reason I had to use Subsetstring was because Substring's overload already takes two ints. If anyone has a better name, please, let me know!!

BFree
I can NOT understand why I haven't done this myself. +1
Torbjørn
Perhaps you could use a name such as SubstringBetween or even just Between.
Drew Noakes
@peSHlr: It's all good if you want to edit a post, but actually CHANGING code, because you think that's the better exception, I think that's a bit much. I won't revert, but I think that's going a bit too far.
BFree
That's wiki-ness for ya!
Cheeso
How about .Range()?
Robert Harvey
.Substring2() .
tsilb
A: 

String.format should not have been static. So I use an extension method called frmt:

<Extension()> Public Function frmt(ByVal format As String,
                                   ByVal ParamArray args() As Object) As String
    If format Is Nothing Then Throw New ArgumentNullException("format")
    Return String.Format(format, args)
End Function

When I want to read or write a number to a byte stream without constructing a binary writer (technically you aren't supposed to modify the raw stream after you've wrapped it with a writer):

<Extension()> Public Function Bytes(ByVal n As ULong,
                                    ByVal byteOrder As ByteOrder,
                                    Optional ByVal size As Integer = 8) As Byte()
    Dim data As New List(Of Byte)
    Do Until data.Count >= size
        data.Add(CByte(n And CULng(&HFF)))
        n >>= 8
    Loop
    Select Case byteOrder
        Case ByteOrder.BigEndian
            Return data.ToArray.reversed
        Case ByteOrder.LittleEndian
            Return data.ToArray
        Case Else
            Throw New ArgumentException("Unrecognized byte order.")
    End Select
End Function
<Extension()> Public Function ToULong(ByVal data As IEnumerable(Of Byte),
                                      ByVal byteOrder As ByteOrder) As ULong
    If data Is Nothing Then Throw New ArgumentNullException("data")
    Dim val As ULong
    Select Case byteOrder
        Case ByteOrder.LittleEndian
            data = data.Reverse
        Case ByteOrder.BigEndian
            'no change required
        Case Else
            Throw New ArgumentException("Unrecognized byte order.")
    End Select
    For Each b In data
        val <<= 8
        val = val Or b
    Next b
    Return val
End Function
Strilanc
+15  A: 

This is one that's been getting some play from me lately:

public static IDisposable Tag(this HtmlHelper html, string tagName)
{
    if (html == null)
        throw new ArgumentNullException("html");

    Action<string> a = tag => html.Write(String.Format(tag, tagName));
    a("<{0}>");
    return new Memento(() => a("</{0}>"));
}

Used like:

using (Html.Tag("ul"))
{
    this.Model.ForEach(item => using(Html.Tag("li")) Html.Write(item)));
    using(Html.Tag("li")) Html.Write("new");
}

Memento is a handy class:

public sealed class Memento : IDisposable
{
    private bool Disposed { get; set; }
    private Action Action { get; set; }

    public Memento(Action action)
    {
        if (action == null)
            throw new ArgumentNullException("action");

        Action = action;
    }

    void IDisposable.Dispose()
    {
        if (Disposed)
            throw new ObjectDisposedException("Memento");

        Disposed = true;
        Action();
    }
}

And to complete the dependencies:

public static void Write(this HtmlHelper html, string content)
{
    if (html == null)
        throw new ArgumentNullException("html");

    html.ViewContext.HttpContext.Response.Write(content);
}
Talljoe
This is nice! (Don't know why someone downvoted it) Maybe the example doesn't make sense for those who aren't into ASP.NET MVC yet :)
DSO
Nice pattern going on here. Thanks. +1
Drew Noakes
Very cool, thanks for the help with my extension too by the way +1
rmoore
I love this! Definitely going in my toolbox!
jrista
I like this idea, but I'm not sure why Memento is throwing an exception from its Dispose method. According to MSDN: "To help ensure that resources are always cleaned up appropriately, a Dispose method should be callable multiple times without throwing an exception." http://bit.ly/NV3AH
Joel Mueller
True, definitely an implementation of this could be made where subsequent calls to Dispose don't throw (don't do anything). In this case I decided that because we're not dealing with a resource so much as a state that gets restored that it's a bug to call Dispose() twice (unexpected behavior).There's a completely separate discussion to be had whether it's a good idea to co-opt the Dispose() pattern to deal with something other than resources. :)
Talljoe
Using the dispose pattern for something other than resources is an often argued issue with no clear winners on either side. That being said, it is still a bad idea to throw an exception as you really have no control over how many times the Dispose method will get called. Imagine what would happen if someone called Memento inside a using statement and also explicitly called Dispose. You end up with two calls to Dispose - one explicit by the user and the other added when the compiler expanded the using statement. The better option would probably be to use an Assert.
Scott Dorman
+1  A: 

cool, also loving Extensions!

here's a few.

This one will get the last Date of a Month:

<System.Runtime.CompilerServices.Extension()> _
    Public Function GetLastMonthDay(ByVal Source As DateTime) As DateTime
        Dim CurrentMonth As Integer = Source.Month
        Dim MonthCounter As Integer = Source.Month
        Dim LastDay As DateTime
        Dim DateCounter As DateTime = Source

        LastDay = Source

        Do While MonthCounter = CurrentMonth
            DateCounter = DateCounter.AddDays(1)
            MonthCounter = DateCounter.Month

            If MonthCounter = CurrentMonth Then
                LastDay = DateCounter
            End If
        Loop

        Return LastDay
    End Function

these two make reflection a bit easier:

 <System.Runtime.CompilerServices.Extension()> _
    Public Function GetPropertyValue(Of ValueType)(ByVal Source As Object, ByVal PropertyName As String) As ValueType
        Dim pInfo As System.Reflection.PropertyInfo

        pInfo = Source.GetType.GetProperty(PropertyName)

        If pInfo Is Nothing Then
            Throw New Exception("Property " & PropertyName & " does not exists for object of type " & Source.GetType.Name)
        Else
            Return pInfo.GetValue(Source, Nothing)
        End If
    End Function

    <System.Runtime.CompilerServices.Extension()> _
    Public Function GetPropertyType(ByVal Source As Object, ByVal PropertyName As String) As Type
        Dim pInfo As System.Reflection.PropertyInfo

        pInfo = Source.GetType.GetProperty(PropertyName)

        If pInfo Is Nothing Then
            Throw New Exception("Property " & PropertyName & " does not exists for object of type " & Source.GetType.Name)
        Else
            Return pInfo.PropertyType
        End If
    End Function
andy
You might split this into two separate answers. It's the SO way!
Drew Noakes
... That GetLastMonthDay implementation is horrific! One line: return source.AddMonths(1).AddDays(-(source.Day + 1));
Task
A: 

This one shifts a sequence so that you get the given item first. I used it for example to take the day of weeks and shift it so that the first day in the sequence is the first day of the week for the current culture.

    /// <summary>
    /// Shifts a sequence so that the given <paramref name="item"/> becomes the first. 
    /// Uses the specified equality <paramref name="comparer"/> to find the item.
    /// </summary>
    /// <typeparam name="TSource">Type of elements in <paramref name="source"/>.</typeparam>
    /// <param name="source">Sequence of elements.</param>
    /// <param name="item">Item which will become the first.</param>
    /// <param name="comparer">Used to find the first item.</param>
    /// <returns>A shifted sequence. For example Shift({1,2,3,4,5,6}, 3) would become {3,4,5,6,1,2}. </returns>
    public static IEnumerable<TSource> Shift<TSource>(this IEnumerable<TSource> source, TSource item, IEqualityComparer<TSource> comparer)
    {
        var queue = new Queue<TSource>();
        bool found = false;

        foreach (TSource e in source)
        {
            if (!found && comparer.Equals(item, e))
                found = true;

            if (found)
                yield return e;
            else
                queue.Enqueue(e);
        }

        while (queue.Count > 0)
            yield return queue.Dequeue();
    }


    /// <summary>
    /// Shifts a sequence so that the given item becomes the first. 
    /// Uses the default equality comparer to find the item.
    /// </summary>
    /// <typeparam name="TSource">Type of elements in <paramref name="source"/>.</typeparam>
    /// <param name="source">Sequence of elements.</param>
    /// <param name="element">Element which will become the first.</param>
    /// <returns>A shifted sequence. For example Shift({1,2,3,4,5,6}, 3) would become {3,4,5,6,1,2}. </returns>
    public static IEnumerable<TSource> Shift<TSource>(this IEnumerable<TSource> source, TSource element)
    {
        return Shift(source, element, EqualityComparer<TSource>.Default);
    }
Svish
+1  A: 

The extension methods I use the most would have to be the ones in the System.Linq.Enumerable class.

And a good and useful extension to that list you can find in MoreLinq.

Svish
+4  A: 

Most examples for extension methods that I see here go against best practises. Extension methods are powerful, but should be used sparingly. In my experience, a static helper/utility class with old-school syntax would generally be preferrable for most of these.

There is something to say for extension methods for Enums, as it's not possible for them to have methods. If you define them in the same namespace as your Enum and in the same assembly, they work transparently.

Thorarin
+5  A: 

I wrote a series of extension methods to make it easier to manipulate ADO.NET objects and methods :

Create a DbCommand from a DbConnection in one instruction :

    public static DbCommand CreateCommand(this DbConnection connection, string commandText)
    {
        DbCommand command = connection.CreateCommand();
        command.CommandText = commandText;
        return command;
    }

Add a parameter to a DbCommand :

    public static DbParameter AddParameter(this DbCommand command, string name, DbType dbType)
    {
        DbParameter p = AddParameter(command, name, dbType, 0, ParameterDirection.Input);
        return p;
    }

    public static DbParameter AddParameter(this DbCommand command, string name, DbType dbType, object value)
    {
        DbParameter p = AddParameter(command, name, dbType, 0, ParameterDirection.Input);
        p.Value = value;
        return p;
    }

    public static DbParameter AddParameter(this DbCommand command, string name, DbType dbType, int size)
    {
        return AddParameter(command, name, dbType, size, ParameterDirection.Input);
    }

    public static DbParameter AddParameter(this DbCommand command, string name, DbType dbType, int size, ParameterDirection direction)
    {
        DbParameter parameter = command.CreateParameter();
        parameter.ParameterName = name;
        parameter.DbType = dbType;
        parameter.Direction = direction;
        parameter.Size = size;
        command.Parameters.Add(parameter);
        return parameter;
    }

Access DbDataReader fields by name rather than index :

    public static DateTime GetDateTime(this DbDataReader reader, string name)
    {
        int i = reader.GetOrdinal(name);
        return reader.GetDateTime(i);
    }

    public static decimal GetDecimal(this DbDataReader reader, string name)
    {
        int i = reader.GetOrdinal(name);
        return reader.GetDecimal(i);
    }

    public static double GetDouble(this DbDataReader reader, string name)
    {
        int i = reader.GetOrdinal(name);
        return reader.GetDouble(i);
    }

    public static string GetString(this DbDataReader reader, string name)
    {
        int i = reader.GetOrdinal(name);
        return reader.GetString(i);
    }

    ...

Another (unrelated) extension method allows me to perform the DragMove operation (like in WPF) on WinForms forms and controls, see here.

Thomas Levesque
+1  A: 

There are a couple that I've mentioned here that I use:

Keith
A: 

I autopilot the following to solve the class-name-to-upper-case-url problem in MVC projects:

public static class RouteCollectionExt
{
    public static Route MapRouteLowercase(this RouteCollection routes, string name, string url, object defaults)
    {
     var route = new LowercaseRoute(url, new RouteValueDictionary(defaults), new MvcRouteHandler());

     routes.Add(name, route);

     return route;
    }

    private class LowercaseRoute : Route
    {
     public LowercaseRoute(string url, IRouteHandler routeHandler)
      : base(url, routeHandler) { }

     public LowercaseRoute(string url, RouteValueDictionary defaults, IRouteHandler routeHandler)
      : base(url, defaults, routeHandler) { }

     public LowercaseRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler)
      : base(url, defaults, constraints, routeHandler) { }

     public LowercaseRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler)
      : base(url, defaults, constraints, dataTokens, routeHandler) { }

     public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
     {
      var path = base.GetVirtualPath(requestContext, values);

      if (path != null)
      {
       path.VirtualPath = path.VirtualPath.ToLowerInvariant();
      }

      return path;
     }
    }  
}

Usage:

routes.MapRouteLowercase(
  "Default",
  "{controller}/{action}/{id}",
  new { controller = "Home", action = "Index", id = "" } 
);
annakata
+3  A: 

While very simple, I find this one to be particularly useful since I get a page out of a full result set ten billion times a project:

public static class QueryableExtensions
{
    public static IQueryable<T> Page(this IQueryable<T> query, int pageNumber, int pageSize)
    {
        int skipCount = (pageNumber-1) * pageSize;
        query = query.Skip(skipCount);
        query = query.Take(pageSize);

        return query;
    }
}
jrista
A: 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string guid1 = "936DA01F-9ABD-4d9d-80C7-02AF85C822A8";
            string guid2 = "936DA01F-9ABD-4d9d-80C7-02AF85C822A";
            Console.WriteLine("guid1: {0}", guid1.IsGuid());
            Console.WriteLine("guid2: {0}", guid2.IsGuid());
            Console.ReadLine();
        }
    }

    public static class GuidUtility
    {
        /// <summary>
        /// Determines if string is legitimate GUID
        /// </summary>       
        public static Boolean IsGuid(this String s)
        {
            string pattern = @"^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$";
            Regex regex = new Regex(pattern);
            return regex.IsMatch(s);
        }
    }
}
Very nice. I'd have thought for sure that there'd be a Guid.TryParse(). I've been proven wrong!
Pwninstein
You should change the regex to allow optional curly braces {936DA01F-9ABD-4d9d-80C7-02AF85C822A8} as well since that is a valid (and probably more common) format as well.
Scott Dorman
+1  A: 

few extensions I use mostly. first set is object extensions, really only for converting.

public static class ObjectExtension
{
 public static T As<T>(this object value)
 {
  return (value != null && value is T) ? (T)value : default(T);
 }

 public static int AsInt(this string value)
 {
  if (value.HasValue())
  {
   int result;

   var success = int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out result);

   if (success)
   {
    return result;
   }
  }

  return 0;
 }

 public static Guid AsGuid(this string value)
 {
  return value.HasValue() ? new Guid(value) : Guid.Empty;
 }
}

string extensions

public static class StringExtension
{
 public static bool HasValue(this string value)
 {
  return string.IsNullOrEmpty(value) == false;
 }

 public static string Slug(this string value)
 {
  if (value.HasValue())
  {
   var builder = new StringBuilder();
   var slug = value.Trim().ToLower();

   foreach (var c in slug)
   {
    switch (c)
    {
     case ' ':
      builder.Append("-");
      break;
     case '&':
      builder.Append("and");
      break;
     default:

      if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') && c != '-')
      {
       builder.Append(c);
      }

      break;
    }
   }

   return builder.ToString();
  }

  return string.Empty;
 }

 public static string Truncate(this string value, int limit)
 {
  return (value.Length > limit) ? string.Concat(value.Substring(0, Math.Min(value.Length, limit)), "...") : value;
 }
}

and last is some enum extensions

public static class EnumExtensions
{
 public static bool Has<T>(this Enum source, params T[] values)
 {
  var value = Convert.ToInt32(source, CultureInfo.InvariantCulture);

  foreach (var i in values)
  {
   var mask = Convert.ToInt32(i, CultureInfo.InvariantCulture);

   if ((value & mask) == 0)
   {
    return false;
   }
  }

  return true;
 }

 public static bool Has<T>(this Enum source, T values)
 {
  var value = Convert.ToInt32(source, CultureInfo.InvariantCulture);
  var mask = Convert.ToInt32(values, CultureInfo.InvariantCulture);

  return (value & mask) != 0;
 }

 public static T Add<T>(this Enum source, T v)
 {
  var value = Convert.ToInt32(source, CultureInfo.InvariantCulture);
  var mask = Convert.ToInt32(v, CultureInfo.InvariantCulture);

  return Enum.ToObject(typeof(T), value | mask).As<T>();
 }

 public static T Remove<T>(this Enum source, T v)
 {
  var value = Convert.ToInt32(source, CultureInfo.InvariantCulture);
  var mask = Convert.ToInt32(v, CultureInfo.InvariantCulture);

  return Enum.ToObject(typeof(T), value & ~mask).As<T>();
 }

 public static T AsEnum<T>(this string value)
 {
  try
  {
   return Enum.Parse(typeof(T), value, true).As<T>();
  }
  catch
  {
   return default(T);
  }
 }
}
Mike Geise
+1 Awesome! I'm unfamiliar with the term "slug" when dealing with strings. Care to share how you would use this particular method? Thanks!
Pwninstein
Mike Geise
Gotcha. Thanks!!
Pwninstein
Why not just call HttpUtility.UrlEncode() ?
tsilb
@tslib its all about seo that is why we slug strings in the first place.
Mike Geise
+2  A: 

To allow more functional combinator code:

    public static Func<T, R> TryCoalesce<T, R>(this Func<T, R> f, R coalesce)
    {
        return x =>
            {
                try
                {
                    return f(x);
                }
                catch
                {
                    return coalesce;
                }
            };
    }
    public static TResult TryCoalesce<T, TResult>(this Func<T, TResult> f, T p, TResult coalesce)
    {
        return f.TryCoalesce(coalesce)(p);
    }

Then I could write something like this:

    public static int ParseInt(this string str, int coalesce)
    {
        return TryCoalesce(int.Parse, str, coalesce);
    }
eulerfx
The problem is, that this will make your code unreliable in the face of fatal exceptions (AccessViolation, ExecutionEngineException, OutOufMemoryException, ...) because auf the unqualified "catch".
Christian.K
Most code tends to be unreliable when it runs out of memory...
Isaac Cambron
+2  A: 

Another set I use quite often is for coalescing IDictionary methods:

    public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> d, TKey key, Func<TValue> valueThunk)
    {
        TValue v = d.Get(key);
        if (v == null)
        {
            v = valueThunk();
            d.Add(key, v);
        }
        return v;
    }
    public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> d, TKey key, TValue coalesce)
    {
        return Get(d, key, () => coalesce);
    }

And for working with collections in general:

    public static IEnumerable<T> AsCollection<T>(this T item)
    {
        yield return item;
    }

Then for tree-like structures:

    public static LinkedList<T> Up<T>(this T node, Func<T, T> parent)
    {
        var list = new LinkedList<T>();
        node.Up(parent, n => list.AddFirst(n));
        return list;
    }

So I can then easily traverse and operate upon a up a class like:

class Category
{
    public string Name { get; set; }
    public Category Parent { get; set; }
}

Next, to facilitate function composition and a more F# like way of programming in C#:

public static Func<T, T> Func<T>(this Func<T, T> f)
{
    return f;
}
public static Func<T1, R> Compose<T1, T2, R>(this Func<T1, T2> f, Func<T2, R> g)
{
    return x => g(f(x));
}
eulerfx
A: 

With regular use of StringBuilder, you may see the need to combine AppendFormat() and AppendLine().

public static void AppendFormatLine(this StringBuilder sb, string format, params object[] args)
{
    sb.AppendFormat(format, args);
    sb.AppendLine();
}

Also, since I'm converting an application from VB6 to C#, the following are very useful to me:

public static string Left(this string s, int length)
{
    if (s.Length >= length)
     return s.Substring(0, length);
    throw new ArgumentException("Length must be less than the length of the string.");
}
public static string Right(this string s, int length)
{
    if (s.Length >= length)
     return s.Substring(s.Length - length, length);
    throw new ArgumentException("Length must be less than the length of the string.");
}
opedog
+4  A: 

This is an extension method to centralize null checks before raising events.

public static class EventExtension
{
    public static void RaiseEvent<T>(this EventHandler<T> handler, object obj, T args) where T : EventArgs
    {
        EventHandler<T> theHandler = handler;

        if (theHandler != null)
        {
            theHandler(obj, args);
        }
    }
}
Taylor Leese
+1. But before checking for nullity, you should first copy the instance of the event handler to a local variable (an event handler instance is immutable). This would prevent some potential race condition in a multi-thread environment (another thread might have unsubscribed after the nullity check, but before the handler be invoked)
Yann Trevin
That is true. I do that in my own code, but never came back to change this answer. I edited my answer.
Taylor Leese
+3  A: 

Often times, I've needed to display a user-friendly value based on an Enum value, but didn't want to go the custom Attribute route, as it didn't seem too elegant.

With this handy extension method:

public static string EnumValue(this MyEnum e) {
    switch (e) {
        case MyEnum.First:
            return "First Friendly Value";
        case MyEnum.Second:
            return "Second Friendly Value";
        case MyEnum.Third:
            return "Third Friendly Value";
    }
    return "Horrible Failure!!";
}

I can do this:

Console.WriteLine(MyEnum.First.EnumValue());

Yay!

Pwninstein
+1  A: 

This one is incredibly simple, but it's a check I do a lot so I ended up making an extension method for it. My favorite extension methods tend to be the really simple, straightforward ones like this, or like Taylor L's extension method for raising events.

public static bool IsNullOrEmpty(this ICollection e)
{
    return e == null || e.Count == 0;
}
Sterno
A: 

I am converting a lot of Java to C#. Many of the methods vary only in capitalization or other small syntax differences. So Java code such as

myString.toLowerCase();

will not compile but by adding an extension method

public static void toLowerCase(this string s)
{
    s.ToLower();
}

I can catch all the methods (and I assume a good compiler will inline this anyway?).

It's certainly made the job much easier and more reliable. (I thank @Yuriy - see answer in: http://stackoverflow.com/questions/1548296/differences-between-stringbuilder-in-java-and-c) for the suggestion.

peter.murray.rust
A: 

Ever worked with Entity Framework & used a line of code similar to this over and over?

_context.EmployeeSet.Include("Department")
    .Include("Manager").Include( ... ).Select();

Isn't it easier to do this:

_context.EmployeeSet.IncludeCommonReferenceses().Select();

`

internal static class ObjectContextExtensions
{
    internal static ObjectQuery<Employee> IncludeCommonReferenceses(this ObjectQuery<Employee> employeeSet)
    {
        return employeeSet.Include(GetPropertyName<Employee>(e => e.Department))
           .Include(GetPropertyName<Employee>(e => e.Manager)).Include( ... );
    }

    private static string GetPropertyName<T>(Expression<Func<T, object>> subSelector)
    {
        return ((MemberExpression)subSelector.Body).Member.Name;
    }
}

I Recommend you save the property names in consts to avoid using reflection over & over agasin.

HuBeZa
+1  A: 

My favourite from my own personal collection of string utils is one that will parse a strongly typed value from a string for any type that has a TryParse method:

public static class StringUtils
{
    /// <summary>
    /// This method will parse a value from a string.
    /// If the string is null or not the right format to parse a valid value,
    /// it will return the default value provided.
    /// </summary>
    public static T To<t>(this string value, T defaultValue)
        where T: struct
    {
        var type = typeof(T);
        if (value != null)
        {
            var parse = type.GetMethod("TryParse", new Type[] { typeof(string), type.MakeByRefType() });
            var parameters = new object[] { value, default(T) };
            if((bool)parse.Invoke(null, parameters))
                return (T)parameters[1];
        }
        return defaultValue;
    }

    /// <summary>
    /// This method will parse a value from a string.
    /// If the string is null or not the right format to parse a valid value,
    /// it will return the default value for the type.
    /// </summary>
    public static T To<t>(this string value)
        where T : struct
    {
        return value.To<t>(default(T));
    }
}

It's great for getting strongly typed information from query strings:

var value = Request.QueryString["value"].To<int>();
Helephant
+1  A: 

I hate having to do this everywhere:

DataSet ds = dataLayer.GetSomeData(1, 2, 3);
if(ds != null){
    if(ds.Tables.Count > 0){
        DataTable dt = ds.Tables[0];
        foreach(DataRow dr in dt.Rows){
            //Do some processing
        }
    }
}

Instead I usually use the following Extension Method:

public static IEnumerable<DataRow> DataRows(this DataSet current){
    if(current != null){
        if(current.Tables.Count > 0){
            DataTable dt = current.Tables[0];
            foreach(DataRow dr in dt.Rows){
                yield return dr;
            }
        }
    }
}

So the first example then becomes:

foreach(DataRow row in ds.DataRows()){
    //Do some processing
}

Yay, Extension Methods!

Pwninstein
How often do your datasets have > 1 tables? Just use foreach (DataRow dr in ds.Tables[0].Rows)
tsilb
+3  A: 

I'm not a fan of the INotifyPropertyChanged interface requiring that property names are passed as strings. I want a strongly-typed way to check at compile time that I'm only raising and handling property changes for properties that exist. I use this code to do that:

public static class INotifyPropertyChangedExtensions
{
    public static string ToPropertyName<T>(this Expression<Func<T>> @this)
    {
        var @return = string.Empty;
        if (@this != null)
        {
            var memberExpression = @this.Body as MemberExpression;
            if (memberExpression != null)
            {
                @return = memberExpression.Member.Name;
            }
        }
        return @return;
    }
}

In classes that implement INotifyPropertyChanged I include this helper method:

protected void NotifySetProperty<T>(ref T field, T value,
    Expression<Func<T>> propertyExpression)
{
    if (field == null ? value != null : !field.Equals(value))
    {
        field = value;
        this.NotifyPropertyChanged(propertyExpression.ToPropertyName());
    }
}

So that finally I can do this kind of thing:

private string _name;
public string Name
{
    get { return _name; }
    set { this.NotifySetProperty(ref _name, value, () => this.Name); }
}

It's strongly-typed and I only raise events for properties that actually change their value.

Enigmativity
I use variables like `private static readonly PropertyChangedEventArgs _namePropertyChangedEventArgs = new PropertyChangedEventArgs("Name");`, and pass those to `OnPropertyChanged`. Much easier to keep track of than strings (find all references), and much cheaper on memory (only created once per type instead of once per change per instance).
280Z28
Hi 280Z28, perhaps a combination of techniques would be useful as your approach still has a string literal that needs updating. In practice I find that the approach I use is fine, especially because the property changes are usually user generated and are therefore slow and infrequent. I will have to check to make sure I'm not creating a memory leak though. Thanks.
Enigmativity
A: 

Compare any given property of the given fileinfo class against another one..

    public static bool compare(this FileInfo F1,FileInfo F2,string propertyName)
    {
        try
        {
            System.Reflection.PropertyInfo p1 = F1.GetType().GetProperty(propertyName);
            System.Reflection.PropertyInfo p2 = F2.GetType().GetProperty(propertyName);

                if (p1.GetValue(F1, null) == p2.GetValue(F1, null))
                {
                    return true;
                }

        }
        catch (Exception ex)
        {
            return false;
        }

        return false;
    }
Ramesh Vel
A: 

This is something which I often use to copy from a stream into another stream, especially for copying stuff into a MemoryStream.

public static void CopyStream(this Stream destination, Stream source)
    {
        if (source.CanSeek)
        {
            source.Position = 0;
        }
        int Length = 64000;
        Byte[] buffer = new Byte[Length];
        int bytesRead = source.Read(buffer, 0, Length);
        // write the required bytes
        while (bytesRead > 0)
        {
            destination.Write(buffer, 0, bytesRead);
            bytesRead = source.Read(buffer, 0, Length);
        }
    }

Implementation:

MemoryStream result = new MemoryStream();
Stream s = new FileStream(tempDocFile, FileMode.Open);

result.CopyStream(s);

s.Close();
J. Vermeire
A: 

In multi-threaded WPF applications (for example when you're using sockets or timers) I often have to invoke the GUI thread to change WPF Element attributes. This is ugly bloated code, especially since you need to do it for every method. That's why I made this extension method:

    /// <summary>
    /// Invoke the element's thread using a dispatcher. This is needed for changing WPF element attributes.
    /// </summary>
    /// <param name="dispatcherObject">The element of which to use the thread.</param>
    /// <param name="action">The action to do with the invoked thread.</param>
    /// <param name="dispatcherPriority">The priority of this action.</param>
    public static void DoInvoked(this System.Windows.Threading.DispatcherObject dispatcherObject, Action action, System.Windows.Threading.DispatcherPriority dispatcherPriority = System.Windows.Threading.DispatcherPriority.Render)
    {
        if (System.Threading.Thread.CurrentThread == dispatcherObject.Dispatcher.Thread)
        {
            action();
        }
        else
        {
            dispatcherObject.Dispatcher.BeginInvoke(action, dispatcherPriority, null);
        }
    }

Implementation:

public partial class MainWindow : Window
{
    ... other code ...
    void updateTime(object sender, ElapsedEventArgs e)
    {
        this.DoInvoked(() => textBoxStatus.Text = "Done.");
    }
}
iNCQRiT
A: 

I'd probably use them most for constrained types.

Something like:

public class Gallons
{
    private int m_gallons;

    public Gallons(int count)
    {
        if(count < 0)
            throw new ArgumentException("Cannot have negative gallons");
        m_gallons = count;
    }

    static public Gallons operator + (Gallons left, Gallons right)
    {
        return new Gallons(left.m_gallons + right.m_gallons);
    }
    public override string ToString()
    {
        return m_gallons.ToString();
    }
}
public class Feet
{
    private int m_feet;

    public Feet(int count)
    {
        if(count < 0)
            throw new ArgumentException("Cannot have negative feet");
        m_feet = count;
    }

    static public Feet operator +(Feet left, Feet right)
    {
        return new Feet(left.m_feet + right.m_feet);
    }
    public override string ToString()
    {
        return m_feet.ToString();
    }
}

public static class Conversions
{
    static public Feet Feet(this int i)
    {
        return new Feet(i);
    }
    static public Gallons Gallons(this int i)
    {
        return new Gallons(i);
    }
}

public class Test
{
    static public int Main(string[] args)
    {
        System.Console.WriteLine(2.Feet() + 3.Feet()); // 5
        System.Console.WriteLine(3.Gallons() + 4.Gallons()); // 7
        System.Console.WriteLine(2.Feet() + 3.Gallons()); // doesn't compile - can't add feet to gallons!
        return 0;
    }
}
kyoryu