73

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!

Andrew Eisenberg
  • 28,387
  • 9
  • 92
  • 148
Mark Carpenter
  • 17,445
  • 22
  • 96
  • 149
  • 19
    Your method is mostly a reimplementation of Enumerable.Range (http://msdn.microsoft.com/en-us/library/system.linq.enumerable.range.aspx). The difference is Range takes a start and a count, while yours takes a from and a to. Yours also goes against normal bounding practice (<) by including the high-end (<=). Finally, it can go backwards, but that is rarely necessary in practice. – Matthew Flaschen Jun 05 '09 at 03:56
  • 1
    +1 Hmm, I didn't know that existed, thanks for the link! You're right about the bounding... this was just an example i threw together in a few minutes - the second you try to do "0.To(myList.Count)" you'll get an exception. – Mark Carpenter Jun 05 '09 at 04:08
  • 8
    Goes against normal bounding pratcice? Nonsense. "0 to 16" is always inclusive in speec and concept. In for-loops, it is normal to use max+1 as the number in the condition, simply because the indexes in a 5-item list go 0...4 and it's more meaningful to look at "< 5" than "<= 4". – Sander Jun 05 '09 at 04:57
  • 5
    read here: http://stackoverflow.com/questions/271398/post-your-extension-goodies-for-c-net-codeplex-com-extensionoverflow – tuinstoel Jun 05 '09 at 05:02
  • haha. almost vb.net syntax created with an extension method... – Pondidum Jun 05 '09 at 09:18
  • 6
    I think `for(int x=0; x<=16; ++x)` is more readable to experienced programmers. But, closed ranges tend to be rare. – Tom Hawtin - tackline Jun 05 '09 at 16:22
  • 3
    It's questions like this that make me want to write more C#... – Daniel Huckstep Jul 20 '09 at 01:49

40 Answers40

19

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);
}
johv
  • 4,424
  • 3
  • 26
  • 42
Talljoe
  • 14,593
  • 4
  • 43
  • 39
  • 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 Jun 05 '09 at 06:30
  • Nice pattern going on here. Thanks. +1 – Drew Noakes Jun 05 '09 at 09:16
  • Very cool, thanks for the help with my extension too by the way +1 – rmoore Jun 05 '09 at 23:00
  • I love this! Definitely going in my toolbox! – jrista Jun 06 '09 at 03:24
  • 11
    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 Jul 20 '09 at 02:29
  • 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 Jul 20 '09 at 05:37
  • 1
    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 Aug 23 '09 at 00:48
18

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
  • 44,706
  • 7
  • 102
  • 124
  • 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 Jun 05 '09 at 04:07
13

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
  • 113,464
  • 11
  • 89
  • 172
  • 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). – Sam Harwell Feb 26 '10 at 07:44
  • 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 Feb 28 '10 at 22:59
12

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");
TheVillageIdiot
  • 40,053
  • 20
  • 133
  • 188
John Farrell
  • 24,673
  • 10
  • 77
  • 110
  • Nice, I was always wondering why the did not include that overload for SingleOrDefault and FirstOrDefault, good initiative on adding it! – rmoore Jun 05 '09 at 04:12
  • I made something similar, although I used a Func instead of T as the default. – Svish Jun 05 '09 at 07:28
  • 3
    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 Jun 05 '09 at 13:33
  • 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 Jun 05 '09 at 13:37
  • @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. – John Farrell Jun 05 '09 at 19:08
  • 5
    personally I think it's not much cleaner than .SingleOrDefault()??new Foo() – Johannes Rudolph Feb 26 '10 at 06:42
12

Two that I like to use are the InsertWhere<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 function 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);
            }
        }
    }
Walt Ritscher
  • 6,977
  • 1
  • 28
  • 35
rmoore
  • 15,162
  • 4
  • 59
  • 59
  • 3
    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's version. 2) Call List'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 Jun 05 '09 at 18:26
  • I never even noticed the List.RemoveAll, I simply assumed all of the extensions were extending IList, 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 to Predicate 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 Jun 05 '09 at 18:53
  • 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 Jun 06 '09 at 00:29
11

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
  • 9,954
  • 2
  • 42
  • 50
11

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
  • 105,752
  • 40
  • 168
  • 205
9

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
  • 9,954
  • 2
  • 42
  • 50
  • 2
    Hmm, there needs to be an import function to take your example and directly post it on the daily wtf. (Though I recently consulted with a client that was creating & using custom guids in their db. create a guid, cut off the end and append a timestamp. seriously wtf.) – rmoore Jun 05 '09 at 07:13
  • 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 Jun 06 '09 at 05:23
  • 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 Jun 07 '09 at 21:52
7

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
  • 286,951
  • 70
  • 623
  • 758
5

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
  • 51,004
  • 28
  • 112
  • 141
  • +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 Feb 26 '10 at 07:41
  • That is true. I do that in my own code, but never came back to change this answer. I edited my answer. – Taylor Leese Feb 26 '10 at 14:40
  • 1
    @Yann Trevin: that's unnecessary, because the EventHandler object is already copied once when passed to the extension method as parameter, so there's no race condition. – ShdNx Jun 18 '11 at 18:28
5

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!

Mark Carpenter
  • 17,445
  • 22
  • 96
  • 149
5

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
  • 47,289
  • 11
  • 75
  • 111
5

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
  • 32,447
  • 15
  • 90
  • 130
  • why not write it in one line? – nawfal Nov 25 '12 at 18:33
  • @nawfal: Write what on one line? It is a convenience extension, and you have to compute skipCount....so....? – jrista Nov 26 '12 at 03:30
  • I thought this would read better: `return query.Skip((pageNumber - 1) * pageSize).Take(pageSize)`. Just a matter of taste.. – nawfal Nov 26 '12 at 06:47
  • @nawfal: Well, you are free to reformat however you wish. Personally, I like breaking my statements up, namely for debuggability (i.e. I can set a breakpoint on the int skipCount line and evaluate the number before hand, whereas if you combine it all into one line, debuggability drops considerably. Same goes for the query variable at each line...I can evaluate the results independently as I step through the code.) – jrista Nov 26 '12 at 21:58
  • Ok I agree with int skipcount line. But the Linq should have come in one line, cos breaking it into two is not helping you anyway :) Just my thought – nawfal Nov 26 '12 at 22:04
  • @nawfal: If you want to evaluate only the behavior of the .Skip() query while debugging, then breaking it out improves your ability to do just that. Otherwise, you can only ever evaluate the combination of .Skip and .Take. Returning directly from a single line eliminates the option of evaluating any of that at all during debugging...and only evaluating the entire result. There IS something to be said about writing code that maximizes one's ability to debug code, and debug code at the appropriate location. More statements may seem "cluttered" or "messy"...but it is easier to manage in the end. – jrista Nov 26 '12 at 22:12
  • Writing "debuggable code" does not necessarily mean you WILL need to debug exactly that code. The simple fact of the matter is, though...you never really know what you might need to debug or when. I've made it a habit to always write code this way...more statements with less complexity. It has been a lifesaver more times than I can count, allowing me to quickly identify and resolve problems that otherwise might have required more complex debugging or late evaluation of complex (possibly extremely complex) LINQ statements that make more sense when evaluated individually. – jrista Nov 26 '12 at 22:14
4

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
  • 1,638
  • 2
  • 17
  • 28
2

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: differences between StringBuilder in Java and C#) for the suggestion.

Community
  • 1
  • 1
peter.murray.rust
  • 37,407
  • 44
  • 153
  • 217
2

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
  • 36,769
  • 7
  • 61
  • 83
  • 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 Feb 05 '10 at 05:57
  • 1
    Most code tends to be unreliable when it runs out of memory... –  Feb 26 '10 at 06:57
2

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
  • 36,769
  • 7
  • 61
  • 83
1

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
  • 736
  • 7
  • 21
1

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
  • 16,738
  • 8
  • 39
  • 36
1

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!

Mark Carpenter
  • 17,445
  • 22
  • 96
  • 149
  • How often do your datasets have > 1 tables? Just use foreach (DataRow dr in ds.Tables[0].Rows) – tsilb Jan 30 '10 at 20:16
1

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.

Community
  • 1
  • 1
Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
1

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
  • 9,954
  • 2
  • 42
  • 50
1

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()
okutane
  • 13,754
  • 10
  • 59
  • 67
  • 3
    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 Jun 05 '09 at 06:11
  • 1
    I'm sure I need this. This is used by code where arrays is used widely and their modification is happening rarely. – okutane Jun 05 '09 at 08:45
  • 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 Jun 05 '09 at 09:20
  • 1
    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 Jun 05 '09 at 12:07
1

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!!

peSHIr
  • 6,279
  • 1
  • 34
  • 46
BFree
  • 102,548
  • 21
  • 159
  • 201
1

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
  • 8,775
  • 13
  • 77
  • 122
1

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
  • 152,914
  • 173
  • 462
  • 620
1

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

Community
  • 1
  • 1
Keith
  • 150,284
  • 78
  • 298
  • 434
1

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
  • 825
  • 7
  • 15
0

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
  • 4,715
  • 3
  • 36
  • 58
0

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;
    }
RameshVel
  • 64,778
  • 30
  • 169
  • 213
0

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();
Jens
  • 3,249
  • 2
  • 25
  • 42
0

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.");
    }
}
0

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
  • 12,848
  • 2
  • 29
  • 33
0

Some of these have already been posted but I just wanted to say that I have seen a number of these threads and the votes never match the reality of what is useful. IMO, this is the list of the truly most useful extension methods

someCollection.ForEach(i => i.DoSomething());

This is very very useful because it replaces the built in foreach statement and we all know how often that gets used.

7.CreateSequence();

This just creates a sequence from 0 to 6. There can be other versions such as specifying a starting point and step. This is the second most useful function because it replaces the for loop. Some people have said that this duplicates the Enumerable.Range function, which is true, but one of the things I like with linq is the left to right ordering, so you can do something like this

myCollection.Where(i => i.Something == somethingElse).Count().CreateSequence(). do something else

The next most useful is the CastTo and As. Again they duplicate built in functionality but they preserve the left to right ordering. Note that CastTo is different to Cast in that CastTo works on a single object.

myObject.CastTo<Person>().DoSomething()
myObject.As<Person>()

Then there is the SplitAsEnumerable. This works the same as split but doesn't load everything into memory at once. This is great for parsing large files. It works on a string or a stream.

myFileStream.SplitAsEnumerable("\r\n").Select(line => line.SplitAsEnumerable(","))

The last one is a way to turn a collection into a string. This is great for displaying stuff on the screen or writing to files. eg:

myTextBox.Text = "Top 3 scorers are " + myCollection.OrderBy(i => i.Score).Take(3).FlattenToString(i => i.Score.ToString(), ", ");
MikeKulls
  • 2,979
  • 2
  • 25
  • 30
0

Whilst I did not write these two - I wish I had. Found on http://lostechies.com/jimmybogard/2009/10/16/more-missing-linq-operators/

Append

public static IEnumerable<TSource> Append<TSource>(this IEnumerable<TSource> source, TSource element)
{
    using (IEnumerator<TSource> e1 = source.GetEnumerator())
        while (e1.MoveNext())
            yield return e1.Current;

    yield return element;
}

Prepend

public static IEnumerable<TSource> Prepend<TSource>(this IEnumerable<TSource> source, TSource element)
{
    yield return element;

    using (IEnumerator<TSource> e1 = source.GetEnumerator())
        while (e1.MoveNext())
            yield return e1.Current;
}
Kane
  • 16,471
  • 11
  • 61
  • 86
  • This first one is usefull for Max when a collection might be empty or you wish to specify a minimum, eg MyCollectionOfInts.Append(10).Max(). I also define an Insert method so you can add an item in any location. – MikeKulls Sep 27 '11 at 00:38
0

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

Mark Carpenter
  • 17,445
  • 22
  • 96
  • 149
BFree
  • 102,548
  • 21
  • 159
  • 201
0

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
Craig Gidney
  • 17,763
  • 5
  • 68
  • 136
0

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
  • 152,914
  • 173
  • 462
  • 620
0

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
  • 74,572
  • 17
  • 113
  • 180
0
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);
        }
    }
}
Mark Carpenter
  • 17,445
  • 22
  • 96
  • 149
  • Very nice. I'd have thought for sure that there'd be a Guid.TryParse(). I've been proven wrong! – Mark Carpenter Jun 07 '09 at 07:09
  • 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 Aug 23 '09 at 01:10
  • .net 4.0 has Guid.TryParse() - http://msdn.microsoft.com/en-us/library/system.guid.tryparse.aspx – Ashish Gupta Nov 01 '10 at 18:15