你最喜欢的C#扩展方法是什么?(codeplex.com/extensionoverflow)

478

让我们列出一份答案,其中您可以发布您卓越且最喜欢的扩展方法

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

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

请标记您的答案以接受将代码放入Codeplex项目中。

请发布完整的源代码而不是链接。

Codeplex新闻:

2010年08月24日 Codeplex页面现在在这里:http://extensionoverflow.codeplex.com/

2008年11月11日 XmlSerialize / XmlDeserialize已经实现并通过单元测试

2008年11月11日 还有更多开发人员的空间。;-) 现在加入吧!

2008年11月11日 第三个贡献者加入ExtensionOverflow,欢迎BKristensen

2008年11月11日,FormatWith现已实现通过单元测试

2008年11月09日,第二位贡献者加入了ExtensionOverflow。欢迎chakrit

2008年11月09日,我们需要更多的开发人员。;-)

2008年11月09日,ThrowIfArgumentIsNull现已实现通过单元测试在Codeplex上。


现在第一段代码已经提交到 Codeplex 网站。 - bovium
Erik,不幸的是,现在所有的事情都已经在CodePlex上开始了。请无论如何加入。 - bovium
3
看起来还不错。我对静态类的命名有一点评论。将它们命名为<type>Extensions并不是很具指示性。例如,StringExtensions 既包含格式化内容又包含 XML 内容。我认为更好的做法是根据你扩展的类型来命名类。例如,在 UnixDateTimeConversions 中命名。你可以合理地猜测它包含将时间转换为 Unix 时间及从 Unix 时间转换的方法。这只是一个想法! - ecoffey
请查看以下网址了解有关C#扩展方法的更多信息:http://planetofcoders.com/c-extension-methods/ - Gaurav Agrawal
150个回答

2

使用内置转换的FindControl:

public static T FindControl<T>(this Control control, string id) where T : Control
{
    return (T)control.FindControl(id);
}

这并不是什么惊人的事情,但我觉得它可以让代码更加清晰易懂。

// With extension method
container.FindControl<TextBox>("myTextBox").SelectedValue = "Hello world!";

// Without extension method
((TextBox)container.FindControl("myTextBox")).SelectedValue = "Hello world!";

如果需要的话,这可以放在codeplex项目中。

我宁愿使用 as T 而不是强制转换。 - jpbochi

2
这个非常有用:
    public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> selector)
    {
        if (first == null)
            throw new ArgumentNullException("first");
        if (second == null)
            throw new ArgumentNullException("second");
        if (selector == null)
            throw new ArgumentNullException("selector");

        using (var enum1 = first.GetEnumerator())
        using (var enum2 = second.GetEnumerator())
        {
            while (enum1.MoveNext() && enum2.MoveNext())
            {
                yield return selector(enum1.Current, enum2.Current);
            }
        }
    }

这个功能已经在.NET 4.0版本中被添加到Enumerable类中,但是在3.5版本中使用也很方便。

示例:

var names = new[] { "Joe", "Jane", "Jack", "John" };
var ages = new[] { 42, 22, 18, 33 };

var persons = names.Zip(ages, (n, a) => new { Name = n, Age = a });

foreach (var p in persons)
{
    Console.WriteLine("{0} is {1} years old", p.Name, p.Age);
}

请注意,参数验证不应该与 yield return 相同的方法中。问题在于 ArgumentNullException 将在返回的“查询”迭代开始时抛出。它应该在调用 Zip 方法时抛出。 - jpbochi

2

将字符串每n个字符进行换行。

public static string WrapAt(this string str, int WrapPos)
{
    if (string.IsNullOrEmpty(str))
        throw new ArgumentNullException("str", "Cannot wrap a null string");
    str = str.Replace("\r", "").Replace("\n", "");

    if (str.Length <= WrapPos)
        return str;

    for (int i = str.Length; i >= 0; i--)
        if (i % WrapPos == 0 && i > 0 && i != str.Length)
            str = str.Insert(i, "\r\n");
    return str;
}

2

我一直在寻找一种方式,将我开发的一些东西贡献回社区。

这是我发现非常有用的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();

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

  1. 您需要包含Microsoft.VisualBasic引用
  2. 使用using Microsoft.VisualBasic.FileIO;

示例:

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

或者

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

我不知道是否应该称其为“开放”,但这些扩展功能仍然很好,我很惊讶之前没有人发布它们。 - leviathanbadger

2

NullPartial是ASP MVC的HTML辅助程序。

当传递null Model时,HTML.Partial和HTML.RenderPartial将提供View的Model,如果此部分是强类型的,并且View具有不同的类型,则会抛出异常而不是传递null引用。这些辅助程序允许您指定两个不同的部分,因此可以使视图中的null测试更简洁。

您有权限将此内容包含在Codeplex页面中

public static class nullpartials
    {
        public static MvcHtmlString NullPartial(this HtmlHelper helper, string Partial, string NullPartial, object Model)
        {
            if (Model == null)
                return helper.Partial(NullPartial);
            else
                return helper.Partial(Partial, Model);
        }

        public static MvcHtmlString NullPartial(this HtmlHelper helper, string Partial, string NullPartial, object Model, ViewDataDictionary viewdata)
        {
            if (Model == null)
                return helper.Partial(NullPartial, viewdata);
            else
                return helper.Partial(Partial, Model, viewdata);
        }

        public static void RenderNullPartial(this HtmlHelper helper, string Partial, string NullPartial, object Model)
        {
            if (Model == null)
            {
                helper.RenderPartial(NullPartial);
                return;
            }
            else
            {
                helper.RenderPartial(Partial, Model);
                return;
            }
        }

        public static void RenderNullPartial(this HtmlHelper helper, string Partial, string NullPartial, object Model, ViewDataDictionary viewdata)
        {
            if (Model == null)
            {
                helper.RenderPartial(NullPartial, viewdata);
                return;
            }
            else
            {
                helper.RenderPartial(Partial, Model, viewdata);
                return;
            }
        }
    }

2

受到String.IsNullOrEmpty的启发

为了验证给定的List是否为空或者null

public static bool IsNullOrEmpty<TSource>(this List<TSource> src)
{            
    return (src == null || src.Count == 0);
}

这个是用于验证给定的两个文件和属性是否相同。

public static bool Compare(this FileInfo f1, FileInfo f2, string propertyName)
{
    try
    {
        PropertyInfo p1 = f1.GetType().GetProperty(propertyName);
        PropertyInfo p2 = f2.GetType().GetProperty(propertyName);

        if (p1.GetValue(f1, null) == p2.GetValue(f1, null))
            return true;
    }
    catch (Exception ex)
    {
        return false;
    }
    return false;
}

并且像这样使用它

FileInfo fo = new FileInfo("c:\\netlog.txt");
FileInfo f1 = new FileInfo("c:\\regkey.txt");

fo.compare(f1, "CreationTime");

可以扩展为更通用的形式,如 public static bool CompareByProperty<Tself, Tother>(this Tself self, Tother other, string propertyName),但是您需要更改比较方式以使用 Equals(value1, value2) 而不是 ==,因为 == 比较对象类型的引用:https://dev59.com/23RA5IYBdhLWcg3wzhbZ - Jürgen Steinblock
((src == null || src.Count == 0) ? true : false) == (src == null || src.Count == 0) ((src == null || src.Count == 0)?true:false)==(src == null || src.Count == 0) - Simen Echholt
7
为什么不编写一个接受 IEnumerable<T>IsNullOrEmpty<T>() 方法? - jpbochi
5
顺便说一下,你在末尾添加了“? true : false”导致我取消了对你的点赞。 - jpbochi
1
这应该分成两个独立的答案。第一个没问题(应该是IEnumerable<T>而不是List<T>)。第二个有些可疑。我同意@SchlaWiener的观点,让它变成通用的。我也会去掉catch。如果发生异常,让调用者决定如何处理。 - Greg
1
IsNullOrEmpty方法是个好主意,我经常用它(但使用IEnumerable<T>而不是List<T>)...但我很确定它已经发布过了。关于第二种方法,我没看到限制它为FileInfo的理由。此外,传递一个带有属性名称的字符串是个不好的主意:你可以用委托来做同样的事情,并避免了反射的开销。 - Thomas Levesque

2

简洁地触发事件的方法:

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以来,上述形式是线程安全的,但如果使用旧版本,则需要重新排列和加锁。


这个解决方案存在问题:只有在当前类中声明事件时才能使用它,如果在基类中声明则无法使用... - Thomas Levesque
@Thomas:手动引发事件不也是一样吗?解决方案是使用此处概述的“protected virtual void OnBar(Eventargs e)”模式:http://msdn.microsoft.com/zh-cn/library/hy3sefw3%28VS.80%29.aspx。 - Will Vousden
是的,但我的意思是你的解决方案在一般情况下不起作用。 - Thomas Levesque
实际上,在旧版本中也是线程安全的。我自己也写过相同的方法。 - SLaks
+1 - 我通常不喜欢对空对象使用扩展方法;然而,这是一个非常好的用法! - csharptest.net

2

我已经写了无数个扩展方法,以下是我发现特别有用的一些。欢迎自由实现。

public static class ControlExtenders
{
    /// <summary>
    /// Advanced version of find control.
    /// </summary>
    /// <typeparam name="T">Type of control to find.</typeparam>
    /// <param name="id">Control id to find.</param>
    /// <returns>Control of given type.</returns>
    /// <remarks>
    /// If the control with the given id is not found
    /// a new control instance of the given type is returned.
    /// </remarks>
    public static T FindControl<T>(this Control control, string id) where T : Control
    {
        // User normal FindControl method to get the control
        Control _control = control.FindControl(id);

        // If control was found and is of the correct type we return it
        if (_control != null && _control is T)
        {
            // Return new control
            return (T)_control;
        }

        // Create new control instance
        _control = (T)Activator.CreateInstance(typeof(T));

        // Add control to source control so the
        // next it is found and the value can be
        // passed on itd, remember to hide it and
        // set an ID so it can be found next time
        if (!(_control is ExtenderControlBase))
        {
            _control.Visible = false;
        }
        _control.ID = id;
        control.Controls.Add(_control);

        // Use reflection to create a new instance of the control
        return (T)_control;
    }
}

public static class GenericListExtenders
{
    /// <summary>
    /// Sorts a generic list by items properties.
    /// </summary>
    /// <typeparam name="T">Type of collection.</typeparam>
    /// <param name="list">Generic list.</param>
    /// <param name="fieldName">Field to sort data on.</param>
    /// <param name="sortDirection">Sort direction.</param>
    /// <remarks>
    /// Use this method when a dinamyc sort field is requiered. If the 
    /// sorting field is known manual sorting might improve performance.
    /// </remarks>
    public static void SortObjects<T>(this List<T> list, string fieldName, SortDirection sortDirection)
    {
        PropertyInfo propInfo = typeof(T).GetProperty(fieldName);
        if (propInfo != null)
        {
            Comparison<T> compare = delegate(T a, T b)
            {
                bool asc = sortDirection == SortDirection.Ascending;
                object valueA = asc ? propInfo.GetValue(a, null) : propInfo.GetValue(b, null);
                object valueB = asc ? propInfo.GetValue(b, null) : propInfo.GetValue(a, null);
                return valueA is IComparable ? ((IComparable)valueA).CompareTo(valueB) : 0;
            };
            list.Sort(compare);
        }
    }

    /// <summary>
    /// Creates a pagged collection from generic list.
    /// </summary>
    /// <typeparam name="T">Type of collection.</typeparam>
    /// <param name="list">Generic list.</param>
    /// <param name="sortField">Field to sort data on.</param>
    /// <param name="sortDirection">Sort direction.</param>
    /// <param name="from">Page from item index.</param>
    /// <param name="to">Page to item index.</param>
    /// <param name="copy">Creates a copy and returns a new list instead of changing the current one.</param>
    /// <returns>Pagged list collection.</returns>
    public static List<T> Page<T>(this List<T> list, string sortField, bool sortDirection, int from, int to, bool copy)
    {
        List<T> _pageList = new List<T>();

        // Copy list
        if (copy)
        {
            T[] _arrList = new T[list.Count];
            list.CopyTo(_arrList);
            _pageList = new List<T>(_arrList);
        }
        else
        {
            _pageList = list;
        }

        // Make sure there are enough items in the list
        if (from > _pageList.Count)
        {
            int diff = Math.Abs(from - to);
            from = _pageList.Count - diff;
        }
        if (to > _pageList.Count)
        {
            to = _pageList.Count;
        }

        // Sort items
        if (!string.IsNullOrEmpty(sortField))
        {
            SortDirection sortDir = SortDirection.Descending;
            if (!sortDirection) sortDir = SortDirection.Ascending;
            _pageList.SortObjects(sortField, sortDir);
        }

        // Calculate max number of items per page
        int count = to - from;
        if (from + count > _pageList.Count) count -= (from + count) - _pageList.Count;

        // Get max number of items per page
        T[] pagged = new T[count];
        _pageList.CopyTo(from, pagged, 0, count);

        // Return pagged items
        return new List<T>(pagged);
    }

    /// <summary>
    /// Shuffle's list items.
    /// </summary>
    /// <typeparam name="T">List type.</typeparam>
    /// <param name="list">Generic list.</param>
    public static void Shuffle<T>(this List<T> list)
    {
        Random rng = new Random();
        for (int i = list.Count - 1; i > 0; i--)
        {
            int swapIndex = rng.Next(i + 1);
            if (swapIndex != i)
            {
                T tmp = list[swapIndex];
                list[swapIndex] = list[i];
                list[i] = tmp;
            }
        }
    }

    /// <summary>
    /// Converts generic List to DataTable.
    /// </summary>
    /// <typeparam name="T">Type.</typeparam>
    /// <param name="list">Generic list.</param>
    /// <param name="columns">Name of the columns to copy to the DataTable.</param>
    /// <returns>DataTable.</returns>
    public static DataTable ToDataTable<T>(this List<T> list, string[] columns)
    {
        List<string> _columns = new List<string>(columns);
        DataTable dt = new DataTable();

        foreach (PropertyInfo info in typeof(T).GetProperties())
        {
            if (_columns.Contains(info.Name) || columns == null)
            {
                dt.Columns.Add(new DataColumn(info.Name, info.PropertyType));
            }
        }
        foreach (T t in list)
        {
            DataRow row = dt.NewRow();
            foreach (PropertyInfo info in typeof(T).GetProperties())
            {
                if (_columns.Contains(info.Name) || columns == null)
                {
                    row[info.Name] = info.GetValue(t, null);
                }
            }
            dt.Rows.Add(row);
        }
        return dt;
    }
}

public static class DateTimeExtenders
{
    /// <summary>
    /// Returns number of month from a string representation.
    /// </summary>
    /// <returns>Number of month.</returns>
    public static int MonthToNumber(this DateTime datetime, string month)
    {
        month = month.ToLower();
        for (int i = 1; i <= 12; i++)
        {
            DateTime _dt = DateTime.Parse("1." + i + ".2000");
            string _month = CultureInfo.InvariantCulture.DateTimeFormat.GetMonthName(i).ToLower();
            if (_month == month)
            {
                return i;
            }
        }
        return 0;
    }

    /// <summary>
    /// Returns month name from month number.
    /// </summary>
    /// <returns>Name of month.</returns>
    public static string MonthToName(this DateTime datetime, int month)
    {
        for (int i = 1; i <= 12; i++)
        {
            if (i == month)
            {
                return CultureInfo.InvariantCulture.DateTimeFormat.GetMonthName(i);
            }
        }
        return "";
    }
}

public static class ObjectExtender
{
    public static object CloneBinary<T>(this T originalObject)
    {
        using (var stream = new System.IO.MemoryStream())
        {
            BinaryFormatter binaryFormatter = new BinaryFormatter();
            binaryFormatter.Serialize(stream, originalObject);
            stream.Position = 0;
            return (T)binaryFormatter.Deserialize(stream);
        }
    }

    public static object CloneObject(this object obj)
    {
        using (MemoryStream memStream = new MemoryStream())
        {
            BinaryFormatter binaryFormatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));
            binaryFormatter.Serialize(memStream, obj);
            memStream.Position = 0;
            return binaryFormatter.Deserialize(memStream);
        }
    }
}

public static class StringExtenders
{
    /// <summary>
    /// Returns string as unit.
    /// </summary>
    /// <param name="value">Value.</param>
    /// <returns>Unit</returns>
    public static Unit ToUnit(this string value)
    {
        // Return empty unit
        if (string.IsNullOrEmpty(value))
            return Unit.Empty;

        // Trim value
        value = value.Trim();

        // Return pixel unit
        if (value.EndsWith("px"))
        {
            // Set unit type
            string _int = value.Replace("px", "");

            // Try parsing to int
            double _val = 0;
            if (!double.TryParse(_int, out _val))
            {
                // Invalid value
                return Unit.Empty;
            }

            // Return unit
            return new Unit(_val, UnitType.Pixel);
        }

        // Return percent unit
        if (value.EndsWith("%"))
        {
            // Set unit type
            string _int = value.Replace("%", "");

            // Try parsing to int
            double _val = 0;
            if (!double.TryParse(_int, out _val))
            {
                // Invalid value
                return Unit.Empty;
            }

            // Return unit
            return new Unit(_val, UnitType.Percentage);
        }

        // No match found
        return new Unit();
    }

    /// <summary>
    /// Returns alternative string if current string is null or empty.
    /// </summary>
    /// <param name="str"></param>
    /// <param name="alternative"></param>
    /// <returns></returns>
    public static string Alternative(this string str, string alternative)
    {
        if (string.IsNullOrEmpty(str)) return alternative;
        return str;
    }

    /// <summary>
    /// Removes all HTML tags from string.
    /// </summary>
    /// <param name="html">String containing HTML tags.</param>
    /// <returns>String with no HTML tags.</returns>
    public static string StripHTML(this string html)
    {
        string nohtml = Regex.Replace(html, "<(.|\n)*?>", "");
        nohtml = nohtml.Replace("\r\n", "").Replace("\n", "").Replace("&nbsp;", "").Trim();
        return nohtml;
    }
}

第一个是我最喜欢的,因为它使我能够替换:
Control c = this.FindControl("tbName");
if (c != null)
{
    // Do something with c
    customer.Name = ((TextBox)c).Text;
}

使用这个:

TextBox c = this.FindControl<TextBox>("tbName");
customer.Name = c.Text;

设置默认字符串值:

string str = "";
if (string.IsNullOrEmpty(str))
{
    str = "I'm empty!";
}

Becomes:

str = str.Alternative("I'm empty!");

2

我最常用的扩展程序是一个可以格式化字节数组的工具:

/// <summary>
/// Returns a string representation of a byte array.
/// </summary>
/// <param name="bytearray">The byte array to represent.</param>
/// <param name="subdivision">The number of elements per group,
/// or 0 to not restrict it. The default is 0.</param>
/// <param name="subsubdivision">The number of elements per line,
/// or 0 to not restrict it. The default is 0.</param>
/// <param name="divider">The string dividing the individual bytes. The default is " ".</param>
/// <param name="subdivider">The string dividing the groups. The default is "  ".</param>
/// <param name="subsubdivider">The string dividing the lines. The default is "\r\n".</param>
/// <param name="uppercase">Whether the representation is in uppercase hexadecimal.
/// The default is <see langword="true"/>.</param>
/// <param name="prebyte">The string to put before each byte. The default is an empty string.</param>
/// <param name="postbyte">The string to put after each byte. The default is an empty string.</param>
/// <returns>The string representation.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="bytearray"/> is <see langword="null"/>.
/// </exception>
public static string ToArrayString(this byte[] bytearray,
    int subdivision = 0,
    int subsubdivision = 0,
    string divider = " ",
    string subdivider = "  ",
    string subsubdivider = "\r\n",
    bool uppercase = true,
    string prebyte = "",
    string postbyte = "")
{
    #region Contract
    if (bytearray == null)
        throw new ArgumentNullException("bytearray");
    #endregion

    StringBuilder sb = new StringBuilder(
        bytearray.Length * (2 + divider.Length + prebyte.Length + postbyte.Length) +
        (subdivision > 0 ? (bytearray.Length / subdivision) * subdivider.Length : 0) +
        (subsubdivision > 0 ? (bytearray.Length / subsubdivision) * subsubdivider.Length : 0));
    int groupElements = (subdivision > 0 ? subdivision - 1 : -1);
    int lineElements = (subsubdivision > 0 ? subsubdivision - 1 : -1);
    for (long i = 0; i < bytearray.LongLength - 1; i++)
    {
        sb.Append(prebyte);
        sb.Append(String.Format(CultureInfo.InvariantCulture, (uppercase ? "{0:X2}" : "{0:x2}"), bytearray[i]));
        sb.Append(postbyte);

        if (lineElements == 0)
        {
            sb.Append(subsubdivider);
            groupElements = subdivision;
            lineElements = subsubdivision;
        }
        else if (groupElements == 0)
        {
            sb.Append(subdivider);
            groupElements = subdivision;
        }
        else
            sb.Append(divider);

        lineElements--;
        groupElements--;
    }
    sb.Append(prebyte);
    sb.Append(String.Format(CultureInfo.InvariantCulture, (uppercase ? "{0:X2}" : "{0:x2}"), bytearray[bytearray.LongLength - 1]));
    sb.Append(postbyte);

    return sb.ToString();
}

默认情况下,ToArrayString() 会将字节数组打印为由单个字节组成的长字符串。然而,ToArrayString(4, 16) 将字节分组成每组四个字节,在每行显示16个字节,就像你最喜欢的十六进制编辑器一样。以下内容可以将字节数组格式化为 C# 代码中可用的格式:

byte[] bytearray = new byte[]{ ... };
Console.Write(bytearray.ToArrayString(4, 16, ", ", ",   ", ",\r\n", true, "0x"));

这是我写的内容,所以你可以将它放在Codeplex上。


哇,8个参数(不包括this参数)!在我看来,任何具有超过4个参数的方法都需要重构... - Thomas Levesque

2

我相信这种方法已经被使用过了,但是我经常使用这种方法(以及更简单的变体):

public static bool CompareEx(this string strA, string strB, CultureInfo culture, bool ignoreCase)
{
    return string.Compare(strA, strB, ignoreCase, culture) == 0;
}

你可以用多种方式编写它,但我喜欢它是因为它能快速统一我的字符串比较方法,同时节省了我的代码行数(或字符数)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接