让我们把你的优秀和最喜欢的扩展方法列一个列表。

要求是必须发布完整的代码,以及如何使用它的示例和解释。

基于对这个主题的高度兴趣,我在Codeplex上建立了一个名为extensionoverflow的开源项目。

请将您的回答标记为接受,以便将代码放入Codeplex项目。

请张贴完整的源代码,而不是一个链接。

Codeplex上新闻:

24.08.2010 Codeplex页面现在在这里:http://extensionoverflow.codeplex.com/

11.11.2008 XmlSerialize / XmlDeserialize现在是实现和单元测试。

11.11.2008仍有发展空间。;-)现在就加入!

11.11.2008第三位贡献者加入了ExtensionOverflow,欢迎加入BKristensen

11.11.2008 FormatWith现在是实现和单元测试。

09.11.2008第二个贡献者加入ExtensionOverflow。欢迎来到chakrit。

我们需要更多的开发人员。: -)

09.11.2008 ThrowIfArgumentIsNull现已在Codeplex上实现和单元测试。


当前回答

空格规范化非常有用,特别是在处理用户输入时:

namespace Extensions.String
{
    using System.Text.RegularExpressions;

    public static class Extensions
    {
        /// <summary>
        /// Normalizes whitespace in a string.
        /// Leading/Trailing whitespace is eliminated and
        /// all sequences of internal whitespace are reduced to
        /// a single SP (ASCII 0x20) character.
        /// </summary>
        /// <param name="s">The string whose whitespace is to be normalized</param>
        /// <returns>a normalized string</returns>
        public static string NormalizeWS( this string @this )
        {
            string src        = @this ?? "" ;
            string normalized = rxWS.Replace( src , m =>{
                  bool isLeadingTrailingWS = ( m.Index == 0 || m.Index+m.Length == src.Length ? true : false ) ;
                  string p                 = ( isLeadingTrailingWS ? "" : " " ) ;
                  return p ;
                }) ;

            return normalized ;

        }
        private static Regex rxWS = new Regex( @"\s+" ) ;
    }
}

其他回答

我有一个扩展方法记录异常:

public static void Log(this Exception obj)
{
  //your logging logic here
}

它的用法是这样的:

try
{
    //Your stuff here
}
catch(Exception ex)
{
    ex.Log();
}

[抱歉发了两次;第二个设计得更好:-)]

下面是我们工作代码库中的一个有趣的例子。在作业线程上遍历一个昂贵的lazy-eval枚举对象,并通过一个可观察对象推回结果。

public static IObservable<T> ToAsyncObservable<T>(this IEnumerable<T> @this)
{
    return Observable.Create<T>(observer =>
    {
        var task = new Task(() =>
        {
            try
            {
                @this.Run(observer.OnNext);
                observer.OnCompleted();
            }
            catch (Exception e)
            {
                observer.OnError(e);
            }
        });

        task.Start();

        return () => { };
    });
}

愚蠢的示例:

new DirectoryInfo(@"c:\program files")
    .EnumerateFiles("*", SearchOption.AllDirectories)
    .ToAsyncObservable()
    .BufferWithTime(TimeSpan.FromSeconds(0.5))
    .ObserveOnDispatcher()
    .Subscribe(
        l => Console.WriteLine("{0} received", l.Count),
        () => Console.WriteLine("Done!"));

for (;;)
{
    Thread.Sleep(10);
    Dispatcher.PushFrame(new DispatcherFrame());
}

显然,这个扩展将是无用的,如果你不使用辉煌的响应式扩展!

感谢评论中的Richard,这个扩展方法是不必要的。RX已经有一个扩展方法“tooobservable”,它接受IScheduler。那就用这个吧!

一些用于使用列表的扩展:

/// <summary>
/// Wrap an object in a list
/// </summary>
public static IList<T> WrapInList<T>(this T item)
{
    List<T> result = new List<T>();
    result.Add(item);
    return result;
}

使用如:

myList = someObject.InList();

使IEnumerable包含来自一个或多个源的项,以使IEnumerable更像列表。对于高性能代码来说,这可能不是一个好主意,但对于测试来说很有用:

public static IEnumerable<T> Append<T>(this IEnumerable<T> enumerable, T newItem)
{
    foreach (T item in enumerable)
    {
        yield return item;
    }

    yield return newItem;
}

public static IEnumerable<T> Append<T>(this IEnumerable<T> enumerable, params T[] newItems)
{
    foreach (T item in enumerable)
    {
        yield return item;
    }

    foreach (T newItem in newItems)
    {
        yield return newItem;
    }
}

如使用。

someEnumeration = someEnumeration.Append(newItem);

还有其他可能的变化——例如。

someEnumeration = someEnumeration.Append(otherEnumeration);

如果你正在克隆项目,你可能还想克隆它们的列表:

public static IList<T> Clone<T>(this IEnumerable<T> source) where T: ICloneable
{
    List<T> result = new List<T>();

    foreach (T item in source)
    {
        result.Add((T)item.Clone());
    }

    return result;
}

当我使用ObservableCollection<T>时,我通常使用AddRange方法扩展它。这里的其他答案给出了这个的实现。

如果您愿意,可以将此代码放入Codeplex项目中。

ThrowIfArgumentIsNull是做空检查的好方法,我们都应该这样做。

public static class Extensions
{
    public static void ThrowIfArgumentIsNull<T>(this T obj, string parameterName) where T : class
    {
        if (obj == null) throw new ArgumentNullException(parameterName + " not allowed to be null");
    }
}

下面是使用它的方法,它适用于您的命名空间中的所有类或任何您使用该命名空间的地方。

internal class Test
{
    public Test(string input1)
    {
        input1.ThrowIfArgumentIsNull("input1");
    }
}

在CodePlex项目上使用这段代码是可以的。

The Substring method on the string class has always felt inadequate to me. Usually when you do a substring, you know the character(s) from where you want to start, and the charachter(s) where you want to end. Thus, I've always felt that have to specify length as the second parameter is stupid. Therefore, I've written my own extension methods. One that takes a startIndex and an endIndex. And one, that takes a startText (string) and endText (string) so you can just specify the text from where to start the substring, and the text for where to end it.

注意:我不能将方法命名为。net中的Substring,因为我的第一个重载采用了与。net重载中的一个相同的参数类型。因此我将它们命名为Subsetstring。请随意添加到CodePlex…

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 > endIndex)
        {
            throw new InvalidOperationException("End Index must be after Start Index.");
        }

        if (startIndex < 0)
        {
            throw new InvalidOperationException("Start Index must be a positive number.");
        }

        if(endIndex <0)
        {
            throw new InvalidOperationException("End Index must be a positive number.");
        }

        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) || string.IsNullOrEmpty(endText))
        {
            throw new ArgumentException("Start Text and End Text cannot be empty.");
        }
        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);
    }
}

用法:

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

输出:"test for my "