你最喜欢的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个回答

3

希望能够提供Unix时间戳和ISO 8601格式的日期和时间。这在网站和REST服务中被广泛使用。

我在我的Facebook库中使用它。您可以在http://github.com/prabirshrestha/FacebookSharp/blob/master/src/FacebookSharp.Core/FacebookUtils/DateUtils.cs找到源代码。

private static readonly DateTime EPOCH = DateTime.SpecifyKind(new DateTime(1970, 1, 1, 0, 0, 0, 0),DateTimeKind.Utc);

public static DateTime FromUnixTimestamp(long timestamp)
{
    return EPOCH.AddSeconds(timestamp);
}

public static long ToUnixTimestamp(DateTime date)
{
    TimeSpan diff = date.ToUniversalTime() - EPOCH;
    return (long)diff.TotalSeconds;
}

public static DateTime FromIso8601FormattedDateTime(string iso8601DateTime){
    return DateTime.ParseExact(iso8601DateTime, "o", System.Globalization.CultureInfo.InvariantCulture);
}

public static string ToIso8601FormattedDateTime(DateTime dateTime)
{
    return dateTime.ToString("o");
}

欢迎在codeplex项目中使用。


我自己也曾经多次编写了基本相同的代码。 - Greg D
有趣。但不完全是扩展方法。 - fre0n

3

这是我唯一编写并经常使用的扩展。它使得使用System.Net.Mail发送电子邮件更加容易。

public static class MailExtension
{
    // GetEmailCreditial(out strServer) gets credentials from an XML file
    public static void Send(this MailMessage email)
    {
        string strServer = String.Empty;
        NetworkCredential credentials = GetEmailCreditial(out strServer);
        SmtpClient client = new SmtpClient(strServer) { Credentials = credentials };
        client.Send(email);
    }

    public static void Send(this IEnumerable<MailMessage> emails)
    {
        string strServer = String.Empty;
        NetworkCredential credentials = GetEmailCreditial(out strServer);
        SmtpClient client = new SmtpClient(strServer) { Credentials = credentials };
        foreach (MailMessage email in emails)
            client.Send(email);
    }
}

// Example of use: 
new MailMessage("info@myDomain.com","you@gmail.com","This is an important Subject", "Body goes here").Send();
//Assume email1,email2,email3 are MailMessage objects
new List<MailMessage>(){email1, email2, email}.Send();


3

我在我的Web项目中使用这些,主要与MVC一起使用。我编写了几个用于ViewDataTempData的代码片段。

/// <summary>
/// Checks the Request.QueryString for the specified value and returns it, if none 
/// is found then the default value is returned instead
/// </summary>
public static T QueryValue<T>(this HtmlHelper helper, string param, T defaultValue) {
    object value = HttpContext.Current.Request.QueryString[param] as object;
    if (value == null) { return defaultValue; }
    try {
        return (T)Convert.ChangeType(value, typeof(T));
    } catch (Exception) {
        return defaultValue;
    }
}

那么我可以翻译类似这样的内容...

这样我就可以写出类似的东西...

<% if (Html.QueryValue("login", false)) { %>
    <div>Welcome Back!</div>

<% } else { %>
    <%-- Render the control or something --%>

<% } %>

任何人都可以使用它 - 请随意使用。 - hugoware
非常好,可以扩展为先检查查询字符串,然后检查ViewData,再检查SessionState,最后返回默认值。 - John

3
在字符串类上的子字符串方法对我来说一直感觉不够充分。通常,当你做一个子字符串时,你知道你想要从哪里开始的字符和你想要结束的字符。因此,我一直觉得必须指定长度作为第二个参数是愚蠢的。因此,我编写了自己的扩展方法。一个是接受startIndex和endIndex的方法。还有一个,它接受startText(字符串)和endText(字符串),这样你就可以只指定从哪里开始子字符串以及在哪里结束它的文本。
注意:我不能像.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);

输出:"测试我的"

2

我认为我以前看到过这个问题,但在这里找不到相关建议。MS在IDictionary接口上有一个TryGetValue函数,但它返回一个布尔值,并在out参数中给出该值,因此在这里提供一个更简单、更清晰的实现:

public static TVal GetValueOrDefault<TKey, TVal>(this IDictionary<TKey, TVal> d, TKey key) {
  if (d.ContainsKey(key))
    return d[key];
  return default(TVal);
}

2
所有的TryXxx都有一个out参数和bool结果:这就是该模式的全部意义!你的方法应该被称为DefaultGetValue之类的名称,以使其与TryGetValue区分开来。 - Jeroen Wiert Pluimers
1
@Jeroen 同意,尽管我会称其为 GetValueOrDefault,以更符合其他类似方法(如 FirstOrDefault)的命名。 - Davy8
1
好的,知道了。我已按@Davy8的建议将该方法重命名。 - Shaul Behr

2

这是另一个控件扩展,我一直在使用,但不知道之前是否已发布在此处。

public static class ControlExtensions
{
    public static void DoubleBuffer(this Control control) 
    {
        // https://dev59.com/yXVD5IYBdhLWcg3wI36L#77233
        // Taxes: Remote Desktop Connection and painting: http://blogs.msdn.com/oldnewthing/archive/2006/01/03/508694.aspx

        if (System.Windows.Forms.SystemInformation.TerminalServerSession) return;
        System.Reflection.PropertyInfo dbProp = typeof(System.Windows.Forms.Control).GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
        dbProp.SetValue(control, true, null);
    }
}

使用方法:

this.someControl.DoubleBuffer();

2

我实现了一个扩展方法包(可在http://foop.codeplex.com/上获得),其中我经常使用的一些方法包括:

// the most beloved extension method for me is Pipe:
<%= variable.Pipe(x => this.SomeFunction(x)).Pipe(y =>
{
    ...;
    return this.SomeOtherFunction(y);
}) %>

var d = 28.December(2009); // some extension methods for creating DateTime
DateTime justDatePart = d.JustDate();
TimeSpan justTimePart = d.JustTime();
var nextTime = d.Add(5.Hours());

using(StreamReader reader = new StreamReader("lines-of-data-file-for-example")) {
    ...
    // for reading streams line by line and usable in LINQ
    var query = from line in reader.Lines(); 
                where line.Contains(_today)
                select new { Parts = PartsOf(line), Time = _now };
}

500.Sleep();

XmlSerialize and XmlDeserialize

IsNull and IsNotNull

IfTrue, IfFalse and Iff:
true.IfTrue(() => Console.WriteLine("it is true then!");

IfNull and IfNotNull

+1 我特别喜欢 Pipe 方法。不过我不得不下载你的源代码才发现它就像是对单个值进行 Where 操作。能否有人编辑答案,让这一点更加清晰明了? - jpbochi
“Pipe(管道)”与“Where(条件)”不同。“Where”是在数学上和函数式编程语言中的“映射”,它接受一个集合(在.NET中为IEnumerable<T>)和一个函数(在.NET中为委托,可以用Lambda表达式来表示,如x => x > 2;所提供的断言的唯一限制是必须返回布尔值)。“Pipe(管道)”运算符是函数式编程语言中常见的工具。它的主要用途是链接计算(函数调用)。它获取一个值和一个函数(如x => f(x)),然后将该函数应用于该值并返回结果。 - Kaveh Shahbazian
3
我有些担心其中一些我不喜欢。比如500.Sleep(),对我来说有点太晦涩了。我不明白为什么不能用简单的Thread.Sleep()。 - Ian

2

在我所有的项目中,我都会加入两个小东西(有些人可能觉得它们很傻),它们是:

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

并且

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

这让我的代码更加流畅。

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

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

我认为这些会成为非常好的扩展属性;如果我们有了那些的话。


1
这样做是否更好?public static bool IsNull<T>(this T obj) where T : class { return (obj == null); } - Dan Diplo
@Dan Diplo 我认为你的更改不会有任何影响。使用泛型将对象与 null 进行比较并没有任何区别。 - jpbochi
2
使用泛型的优点在于:如果您尝试在结构体上调用Dan Diplo的IsNull()泛型版本,您将会得到一个编译时错误。如果您调用John Kraft的原始版本,则不会警告您(并且还会添加装箱代码)。 - Ray Burns
1
我对结构体的关注感到困惑。按照定义,结构体永远不可能为null。因此,它在结构体上返回false是正确的行为。 - John Kraft
+1,我经常使用这些。我正要发布一个完全相同的答案,直到发现你的答案已经存在:D - demoncodemonkey
显示剩余2条评论

2

将字符串的长度缩短为toLength,并在缩短后的字符串末尾添加一个附加字符串以表示该字符串已被缩短(默认为...)。

public static string Shorten(this string str, int toLength, string cutOffReplacement = " ...")
{
    if (string.IsNullOrEmpty(str) || str.Length <= toLength)
        return str;
    else
        return str.Remove(toLength) + cutOffReplacement;
}

2
添加“...”将返回ShortenToLength + 4个字符,即一个比文档中所述更长的字符串。 - sisve
@Simon - 已修复文档。 @peSHIr - 我已编辑过了,请您详细说明一下。 - Omar

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