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

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

基于对这个主题的高度兴趣,我在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上实现和单元测试。


当前回答

也许我写过和用过的最有用的扩展方法是:

http://www.codeproject.com/KB/cs/fun-with-cs-extensions.aspx?msg=2838918#xx2838918xx

其他回答

我今天刚刚在博客上写了这个。它是INotifyPropertyChanged属性周围的强类型响应式包装器。

GetPropertyValues返回一个IObservable<T>的值,当它们改变时,从当前值开始。如果忽略当前值,可以对结果调用Skip(1)。

用法如下:

IObservable<int> values = viewModel.GetPropertyValues(x => x.IntProperty);

实现:

public static class NotifyPropertyChangeReactiveExtensions
{
    // Returns the values of property (an Expression) as they change, 
    // starting with the current value
    public static IObservable<TValue> GetPropertyValues<TSource, TValue>(
        this TSource source, Expression<Func<TSource, TValue>> property)
        where TSource : INotifyPropertyChanged
    {
        MemberExpression memberExpression = property.Body as MemberExpression;

        if (memberExpression == null)
        {
            throw new ArgumentException(
                "property must directly access a property of the source");
        }

        string propertyName = memberExpression.Member.Name;

        Func<TSource, TValue> accessor = property.Compile();

        return source.GetPropertyChangedEvents()
            .Where(x => x.EventArgs.PropertyName == propertyName)
            .Select(x => accessor(source))
            .StartWith(accessor(source));
    }

    // This is a wrapper around FromEvent(PropertyChanged)
    public static IObservable<IEvent<PropertyChangedEventArgs>>
        GetPropertyChangedEvents(this INotifyPropertyChanged source)
    {
        return Observable.FromEvent<PropertyChangedEventHandler, 
            PropertyChangedEventArgs>(
            h => new PropertyChangedEventHandler(h),
            h => source.PropertyChanged += h,
            h => source.PropertyChanged -= h);
    }
}

我在所有项目中用到的两个小技巧(有些人会觉得很傻)是:

public static bool IsNull(this object o){
  return o == null;
}

and

public static bool IsNullOrEmpty(this string s){
  return string.IsNullOrEmpty(s);
}

它使我的代码更流畅。

if (myClassInstance.IsNull()) //... do something

if (myString.IsNullOrEmpty()) //... do something

我认为这些是很好的扩展属性;如果我们能得到这些。

二分查找:

public static T BinarySearch<T, TKey>(this IList<T> list, Func<T, TKey> keySelector, TKey key)
        where TKey : IComparable<TKey>
{
    int min = 0;
    int max = list.Count;
    int index = 0;
    while (min < max)
    {
        int mid = (max + min) / 2;
        T midItem = list[mid];
        TKey midKey = keySelector(midItem);
        int comp = midKey.CompareTo(key);
        if (comp < 0)
        {
            min = mid + 1;
        }
        else if (comp > 0)
        {
            max = mid - 1;
        }
        else
        {
            return midItem;
        }
    }
    if (min == max &&
        keySelector(list[min]).CompareTo(key) == 0)
    {
        return list[min];
    }
    throw new InvalidOperationException("Item not found");
}

用法(假设列表按Id排序):

var item = list.BinarySearch(i => i.Id, 42);

它抛出InvalidOperationException的事实可能看起来很奇怪,但这就是Enumerable。第一种情况是没有匹配项。

For adding multiple elements to a collection that doesn't have AddRange, e.g., collection.Add(item1, item2, itemN); static void Add<T>(this ICollection<T> coll, params T[] items) { foreach (var item in items) coll.Add(item); } The following is like string.Format() but with custom string representation of arguments, e.g., "{0} {1} {2}".Format<Custom>(c=>c.Name,"string",new object(),new Custom()) results in "string {System.Object} Custom1Name" static string Format<T>( this string format , Func<T,object> select , params object[] args) { for(int i=0; i < args.Length; ++i) { var x = args[i] as T; if (x != null) args[i] = select(x); } return string.Format(format, args); }

这是ThrowIfNull的另一个实现:

[ThreadStatic]
private static string lastMethodName = null;

[ThreadStatic]
private static int lastParamIndex = 0;

[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowIfNull<T>(this T parameter)
{
    var currentStackFrame = new StackFrame(1);
    var props = currentStackFrame.GetMethod().GetParameters();

    if (!String.IsNullOrEmpty(lastMethodName)) {
        if (currentStackFrame.GetMethod().Name != lastMethodName) {
            lastParamIndex = 0;
        } else if (lastParamIndex >= props.Length - 1) {
            lastParamIndex = 0;
        } else {
            lastParamIndex++;
        }
    } else {
        lastParamIndex = 0;
    }

    if (!typeof(T).IsValueType) {
        for (int i = lastParamIndex; i &lt; props.Length; i++) {
            if (props[i].ParameterType.IsValueType) {
                lastParamIndex++;
            } else {
                break;
            }
        }
    }

    if (parameter == null) {
        string paramName = props[lastParamIndex].Name;
        throw new ArgumentNullException(paramName);
    }

    lastMethodName = currentStackFrame.GetMethod().Name;
}

它不像其他实现那样高效,但有更干净的用法:

public void Foo()
{
    Bar(1, 2, "Hello", "World"); //no exception
    Bar(1, 2, "Hello", null); //exception
    Bar(1, 2, null, "World"); //exception
}

public void Bar(int x, int y, string someString1, string someString2)
{
    //will also work with comments removed
    //x.ThrowIfNull();
    //y.ThrowIfNull();
    someString1.ThrowIfNull();
    someString2.ThrowIfNull();

    //Do something incredibly useful here!
}

改变参数为int?也会起作用。