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

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

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


当前回答

在将表单输入放入数据库之前解析表单输入时,这些扩展方法对我来说非常有用

public static int? ToInt(this string input) 
{
    int val;
    if (int.TryParse(input, out val))
        return val;
    return null;
}

public static DateTime? ToDate(this string input)
{
    DateTime val;
    if (DateTime.TryParse(input, out val))
        return val;
    return null;
}

public static decimal? ToDecimal(this string input)
{
    decimal val;
    if (decimal.TryParse(input, out val))
        return val;
    return null;
}

其他回答

比较两个对象的相等性,而不必重写Equals或实现IEquatable<>。

你为什么要这么做?当你真的想知道两个对象是否相等,但你懒得重写Equals(object)或实现IEquatable<T>。或者,更现实地说,如果您有一个非常复杂的类,手工实现Equals将非常乏味、容易出错,维护起来也不有趣。如果您不太关心性能,它也会有所帮助。

我目前使用IsEqualTo是因为第二个原因——我有一个具有许多属性的类,这些属性的类型是其他用户定义的类,每个类都有许多其他属性,这些属性的类型是其他用户定义的类,一直到无限。在许多这样的类中加入一堆集合,实现Equals(object)真的变成了一场噩梦。

用法:

if (myTerriblyComplexObject.IsEqualTo(myOtherTerriblyComplexObject))
{
    // Do something terribly interesting.
}

为了确定相等,我做了很多比较。我尽一切努力按照“正确”的顺序做“正确”的事。比较顺序如下:

Use the static Equals(object, object) method. If it returns true, return true. It will return true if the references are the same. It will also return true if thisObject overrides Equals(object). If thisObject is null, return false. No further comparisons can be made if it is null. If thisObject has overridden Equals(object), return false. Since it overrides Equals, it must mean that Equals was executed at step #1 and returned false. If someone has bothered to override Equals, we should respect that and return what Equals returns. If thisObject inherits from IEquatable<T>, where otherObject can be assigned to T, get the Equals(T) method using reflection. Invoke that method and return its return value. If both objects are IEnumerable, return whether contain the same items, in the same order, using IsEqualTo to compare the items. If the objects have different types, return false. Since we know now that thisObject does not have an Equals method, there isn't any way to realistically evaluate two object of different types to be true. If the objects are a value type (primitive or struct) or a string, return false. We have already failed the Equals(object) test - enough said. For each property of thisObject, test its value with IsEqualTo. If any return false, return false. If all return true, return true.

字符串比较可能更好,但很容易实现。此外,我不能100%确定我处理结构正确。

话不多说,下面是扩展方法:

/// <summary>
/// Provides extension methods to determine if objects are equal.
/// </summary>
public static class EqualsEx
{
    /// <summary>
    /// The <see cref="Type"/> of <see cref="string"/>.
    /// </summary>
    private static readonly Type StringType = typeof(string);

    /// <summary>
    /// The <see cref="Type"/> of <see cref="object"/>.
    /// </summary>
    private static readonly Type ObjectType = typeof(object);

    /// <summary>
    /// The <see cref="Type"/> of <see cref="IEquatable{T}"/>.
    /// </summary>
    private static readonly Type EquatableType = typeof(IEquatable<>);

    /// <summary>
    /// Determines whether <paramref name="thisObject"/> is equal to <paramref name="otherObject"/>.
    /// </summary>
    /// <param name="thisObject">
    /// This object.
    /// </param>
    /// <param name="otherObject">
    /// The other object.
    /// </param>
    /// <returns>
    /// True, if they are equal, otherwise false.
    /// </returns>
    public static bool IsEqualTo(this object thisObject, object otherObject)
    {
        if (Equals(thisObject, otherObject))
        {
            // Always check Equals first. If the object has overridden Equals, use it. This will also capture the case where both are the same reference.
            return true;
        }

        if (thisObject == null)
        {
            // Because Equals(object, object) returns true if both are null, if either is null, return false.
            return false;
        }

        var thisObjectType = thisObject.GetType();
        var equalsMethod = thisObjectType.GetMethod("Equals", BindingFlags.Public | BindingFlags.Instance, null, new[] { ObjectType }, null);
        if (equalsMethod.DeclaringType == thisObjectType)
        {
            // thisObject overrides Equals, and we have already failed the Equals test, so return false.
            return false;
        }

        var otherObjectType = otherObject == null ? null : otherObject.GetType();

        // If thisObject inherits from IEquatable<>, and otherObject can be passed into its Equals method, use it.
        var equatableTypes = thisObjectType.GetInterfaces().Where(                                          // Get interfaces of thisObjectType that...
            i => i.IsGenericType                                                                            // ...are generic...
            && i.GetGenericTypeDefinition() == EquatableType                                                // ...and are IEquatable of some type...
            && (otherObjectType ==  null || i.GetGenericArguments()[0].IsAssignableFrom(otherObjectType))); // ...and otherObjectType can be assigned to the IEquatable's type.

        if (equatableTypes.Any())
        {
            // If we found any interfaces that meed our criteria, invoke the Equals method for each interface.
            // If any return true, return true. If all return false, return false.
            return equatableTypes
                .Select(equatableType => equatableType.GetMethod("Equals", BindingFlags.Public | BindingFlags.Instance))
                .Any(equatableEqualsMethod => (bool)equatableEqualsMethod.Invoke(thisObject, new[] { otherObject }));
        }

        if (thisObjectType != StringType && thisObject is IEnumerable && otherObject is IEnumerable)
        {
            // If both are IEnumerable, check their items.
            var thisEnumerable = ((IEnumerable)thisObject).Cast<object>();
            var otherEnumerable = ((IEnumerable)otherObject).Cast<object>();

            return thisEnumerable.SequenceEqual(otherEnumerable, IsEqualToComparer.Instance);
        }

        if (thisObjectType != otherObjectType)
        {
            // If they have different types, they cannot be equal.
            return false;
        }

        if (thisObjectType.IsValueType || thisObjectType == StringType)
        {
            // If it is a value type, we have already determined that they are not equal, so return false.
            return false;
        }

        // Recurse into each public property: if any are not equal, return false. If all are true, return true.
        return !(from propertyInfo in thisObjectType.GetProperties()
                 let thisPropertyValue = propertyInfo.GetValue(thisObject, null)
                 let otherPropertyValue = propertyInfo.GetValue(otherObject, null)
                 where !thisPropertyValue.IsEqualTo(otherPropertyValue)
                 select thisPropertyValue).Any();
    }

    /// <summary>
    /// A <see cref="IEqualityComparer{T}"/> to be used when comparing sequences of collections.
    /// </summary>
    private class IsEqualToComparer : IEqualityComparer<object>
    {
        /// <summary>
        /// The singleton instance of <see cref="IsEqualToComparer"/>.
        /// </summary>
        public static readonly IsEqualToComparer Instance;

        /// <summary>
        /// Initializes static members of the <see cref="EqualsEx.IsEqualToComparer"/> class.
        /// </summary>
        static IsEqualToComparer()
        {
            Instance = new IsEqualToComparer();
        }

        /// <summary>
        /// Prevents a default instance of the <see cref="EqualsEx.IsEqualToComparer"/> class from being created.
        /// </summary>
        private IsEqualToComparer()
        {
        }

        /// <summary>
        /// Determines whether the specified objects are equal.
        /// </summary>
        /// <param name="x">
        /// The first object to compare.
        /// </param>
        /// <param name="y">
        /// The second object to compare.
        /// </param>
        /// <returns>
        /// true if the specified objects are equal; otherwise, false.
        /// </returns>
        bool IEqualityComparer<object>.Equals(object x, object y)
        {
            return x.IsEqualTo(y);
        }

        /// <summary>
        /// Not implemented - throws an <see cref="NotImplementedException"/>.
        /// </summary>
        /// <param name="obj">
        /// The <see cref="object"/> for which a hash code is to be returned.
        /// </param>
        /// <returns>
        /// A hash code for the specified object.
        /// </returns>
        int IEqualityComparer<object>.GetHashCode(object obj)
        {
            throw new NotImplementedException();
        }
    }
}

简明扼要地提出事件:

public static void Raise(this EventHandler handler, object sender, EventArgs e)
{
    if (handler != null)
    {
        handler(sender, e);
    }
}

public static void Raise<T>(this EventHandler<T> handler, object sender, T e) where T : EventArgs
{
    if (handler != null)
    {
        handler(sender, e);
    }
}

用法:

public event EventHandler Bar;

public void Foo()
{
    Bar.Raise(this, EventArgs.Empty);
}

这里有一些关于潜在线程安全问题的讨论。从。net 4开始,上面的表单是线程安全的,但如果使用旧版本,则需要重新排列和一些锁。

在。net中,有IndexOf和LastIndexOf方法,它们返回String对象中第一个和最后一个匹配项的索引。我有一个扩展方法来获得第n次出现的索引:

public static partial class StringExtensions {

    public static int NthIndexOf(this String str, String match, int occurrence) {
        int i = 1;
        int index = 0;

        while (i <= occurrence && 
            ( index = str.IndexOf(match, index + 1) ) != -1) {

            if (i == occurrence) {
                // Occurrence match found!
                return index;
            }
            i++;
        }

        // Match not found
        return -1;
    }
}

我一直在寻找一种方式来回馈社区我所开发的一些东西。

这里有一些FileInfo扩展,我觉得非常有用。

/// <summary>
/// Open with default 'open' program
/// </summary>
/// <param name="value"></param>
public static Process Open(this FileInfo value)
{
    if (!value.Exists)
        throw new FileNotFoundException("File doesn't exist");
    Process p = new Process();
    p.StartInfo.FileName = value.FullName;
    p.StartInfo.Verb = "Open";
    p.Start();
    return p;
}

/// <summary>
/// Print the file
/// </summary>
/// <param name="value"></param>
public static void Print(this FileInfo value)
{
    if (!value.Exists)
        throw new FileNotFoundException("File doesn't exist");
    Process p = new Process();
    p.StartInfo.FileName = value.FullName;
    p.StartInfo.Verb = "Print";
    p.Start();
}

/// <summary>
/// Send this file to the Recycle Bin
/// </summary>
/// <exception cref="File doesn't exist" />
/// <param name="value"></param>
public static void Recycle(this FileInfo value)
{        
    value.Recycle(false);
}

/// <summary>
/// Send this file to the Recycle Bin
/// On show, if person refuses to send file to the recycle bin, 
/// exception is thrown or otherwise delete fails
/// </summary>
/// <exception cref="File doesn't exist" />
/// <exception cref="On show, if user refuses, throws exception 'The operation was canceled.'" />
/// <param name="value">File being recycled</param>
/// <param name="showDialog">true to show pop-up</param>
public static void Recycle(this FileInfo value, bool showDialog)
{
    if (!value.Exists)
            throw new FileNotFoundException("File doesn't exist");
    if( showDialog )
        FileSystem.DeleteFile
            (value.FullName, UIOption.AllDialogs, 
            RecycleOption.SendToRecycleBin);
    else
        FileSystem.DeleteFile
            (value.FullName, UIOption.OnlyErrorDialogs, 
            RecycleOption.SendToRecycleBin);
}

在用户喜欢的编辑器中打开任意文件:

new FileInfo("C:\image.jpg").Open();

打印任何操作系统知道如何打印的文件:

new FileInfo("C:\image.jpg").Print();

将任何文件发送到回收站:

你必须包括微软。VisualBasic参考 使用Microsoft.VisualBasic.FileIO;

例子:

new FileInfo("C:\image.jpg").Recycle();

Or

// let user have a chance to cancel send to recycle bin.
new FileInfo("C:\image.jpg").Recycle(true);

这个还没有完全烤熟因为我们今天早上才想到。它将为Type生成一个完整的类定义。当您有一个大型类,想要创建一个子集或完整定义,但无法访问它的情况下非常有用。例如,将对象存储在数据库中等等。

public static class TypeExtensions
{
    public static string GenerateClassDefinition(this Type type)
    {
        var properties = type.GetFields();
        var sb = new StringBuilder();
        var classtext = @"private class $name
        {
         $props}";

        foreach (var p in GetTypeInfo(type))
        {
            sb.AppendFormat("  public {0} {1} ", p.Item2, p.Item1).AppendLine(" { get; set; }");
        }

        return classtext.Replace("$name", type.Name).Replace("$props", sb.ToString());
    }

    #region Private Methods
    private static List<Tuple<string, string>> GetTypeInfo(Type type)
    {
        var ret = new List<Tuple<string, string>>();
        var fields = type.GetFields();
        var props = type.GetProperties();

        foreach(var p in props) ret.Add(new Tuple<string, string>(p.Name, TranslateType(p.PropertyType)));    
        foreach(var f in fields) ret.Add(new Tuple<string, string>(f.Name, TranslateType(f.FieldType)));

        return ret;
    }


    private static string TranslateType(Type input)
    {
        string ret;

        if (Nullable.GetUnderlyingType(input) != null)
        {
            ret = string.Format("{0}?", TranslateType(Nullable.GetUnderlyingType(input)));
        }
        else
        {
            switch (input.Name)
            {
                case "Int32": ret = "int"; break;
                case "Int64": ret = "long"; break;
                case "IntPtr": ret = "long"; break;
                case "Boolean": ret = "bool"; break;
                case "String":
                case "Char":
                case "Decimal":
                    ret = input.Name.ToLower(); break;
                default: ret = input.Name; break;
            }
        }

        return ret;
    }
    #endregion
}

使用示例:

Process.GetProcesses().First().GetType().GenerateClassDefinition();

如果使用linqpad,变得更加方便:

Process.GetProcesses().First().GetType().GenerateClassDefinition().Dump();