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

让我们列出你发布你的优秀和最喜欢的扩展方法的答案。

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

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

请将您的答案标记为Codeplex项目中的代码。

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

Codeplex新闻:

24.08.2010 Codeplex页面现在位于: http ://extensionoverflow.codeplex.com/

2008年11月11日XmlSerialize / XmlDeserialize现在已经实现并被unit testing 。

11.11.2008还有更多开发者的空间。 😉 立即join!

11.11.2008第三名贡献者join了ExtensionOverflow ,欢迎来到BKristensen

11.11.2008 FormatWith现在已经实现,并进行了unit testing 。

09.11.2008第二个贡献者join了ExtensionOverflow 。 欢迎来到chakrit 。

09.11.2008我们需要更多的开发者。 😉

09.11.2008 ThrowIfArgumentIsNull现已在Codeplex上实现并进行了unit testing 。

public static bool In<T>(this T source, params T[] list) { if(null==source) throw new ArgumentNullException("source"); return list.Contains(source); } 

允许我replace:

 if(reallyLongIntegerVariableName == 1 || reallyLongIntegerVariableName == 6 || reallyLongIntegerVariableName == 9 || reallyLongIntegerVariableName == 11) { // do something.... } and if(reallyLongStringVariableName == "string1" || reallyLongStringVariableName == "string2" || reallyLongStringVariableName == "string3") { // do something.... } and if(reallyLongMethodParameterName == SomeEnum.Value1 || reallyLongMethodParameterName == SomeEnum.Value2 || reallyLongMethodParameterName == SomeEnum.Value3 || reallyLongMethodParameterName == SomeEnum.Value4) { // do something.... } 

附:

 if(reallyLongIntegerVariableName.In(1,6,9,11)) { // do something.... } and if(reallyLongStringVariableName.In("string1","string2","string3")) { // do something.... } and if(reallyLongMethodParameterName.In(SomeEnum.Value1, SomeEnum.Value2, SomeEnum.Value3, SomeEnum.Value4) { // do something.... } 

我在我的MiscUtil项目中有各种扩展方法(完整的源代码在那里 – 我不打算在这里重复)。 我的最爱,其中一些涉及其他类(如范围):

date和时间的东西 – 主要是unit testing。 不知道我会使用他们在生产:)

 var birthday = 19.June(1976); var workingDay = 7.Hours() + 30.Minutes(); 

范围和步进 – 非常感谢Marc Gravell为他的操作员做的这些事情 :

 var evenNaturals = 2.To(int.MaxValue).Step(2); var daysSinceBirth = birthday.To(DateTime.Today).Step(1.Days()); 

比较:

 var myComparer = ProjectionComparer.Create(Person p => p.Name); var next = myComparer.ThenBy(p => p.Age); var reversed = myComparer.Reverse(); 

参数检查:

 x.ThrowIfNull("x"); 

LINQ to XML应用于匿名types(或具有适当属性的其他types):

 // <Name>Jon</Name><Age>32</Age> new { Name="Jon", Age=32}.ToXElements(); // Name="Jon" Age="32" (as XAttributes, obviously) new { Name="Jon", Age=32}.ToXAttributes() 

推LINQ – 在这里解释需要很长的时间,但要search它。

string.Format快捷键:

 public static class StringExtensions { // Enable quick and more natural string.Format calls public static string F(this string s, params object[] args) { return string.Format(s, args); } } 

例:

 var s = "The co-ordinate is ({0}, {1})".F(point.X, point.Y); 

快速复制并粘贴到这里 。

难道你不觉得键入"some string".F("param")而不是string.Format("some string", "param")更自然吗?

要获得更具可读性的名称,请尝试以下其中一个build议:

 s = "Hello {0} world {1}!".Fmt("Stack", "Overflow"); s = "Hello {0} world {1}!".FormatBy("Stack", "Overflow"); s = "Hello {0} world {1}!".FormatWith("Stack", "Overflow"); s = "Hello {0} world {1}!".Display("Stack", "Overflow"); s = "Hello {0} world {1}!".With("Stack", "Overflow"); 

..

这些有用吗?

 public static bool CoinToss(this Random rng) { return rng.Next(2) == 0; } public static T OneOf<T>(this Random rng, params T[] things) { return things[rng.Next(things.Length)]; } Random rand; bool luckyDay = rand.CoinToss(); string babyName = rand.OneOf("John", "George", "Radio XBR74 ROCKS!"); 
 public static class ComparableExtensions { public static bool Between<T>(this T actual, T lower, T upper) where T : IComparable<T> { return actual.CompareTo(lower) >= 0 && actual.CompareTo(upper) < 0; } } 

例:

 if (myNumber.Between(3,7)) { // .... } 

扩展方法:

 public static void AddRange<T, S>(this ICollection<T> list, params S[] values) where S : T { foreach (S value in values) list.Add(value); } 

该方法适用于所有types,并允许您将一系列项目作为参数添加到列表中。

例:

 var list = new List<Int32>(); list.AddRange(5, 4, 8, 4, 2); 

通过一切手段把这个在codeplex项目。

序列化/反序列化对象到XML:

 /// <summary>Serializes an object of type T in to an xml string</summary> /// <typeparam name="T">Any class type</typeparam> /// <param name="obj">Object to serialize</param> /// <returns>A string that represents Xml, empty otherwise</returns> public static string XmlSerialize<T>(this T obj) where T : class, new() { if (obj == null) throw new ArgumentNullException("obj"); var serializer = new XmlSerializer(typeof(T)); using (var writer = new StringWriter()) { serializer.Serialize(writer, obj); return writer.ToString(); } } /// <summary>Deserializes an xml string in to an object of Type T</summary> /// <typeparam name="T">Any class type</typeparam> /// <param name="xml">Xml as string to deserialize from</param> /// <returns>A new object of type T is successful, null if failed</returns> public static T XmlDeserialize<T>(this string xml) where T : class, new() { if (xml == null) throw new ArgumentNullException("xml"); var serializer = new XmlSerializer(typeof(T)); using (var reader = new StringReader(xml)) { try { return (T)serializer.Deserialize(reader); } catch { return null; } // Could not be deserialized to this type. } } 

ForEach for IEnumerables

 public static class FrameworkExtensions { // a map function public static void ForEach<T>(this IEnumerable<T> @enum, Action<T> mapFunction) { foreach (var item in @enum) mapFunction(item); } } 

天真的例子:

 var buttons = GetListOfButtons() as IEnumerable<Button>; // click all buttons buttons.ForEach(b => b.Click()); 

很酷的例子:

 // no need to type the same assignment 3 times, just // new[] up an array and use foreach + lambda // everything is properly inferred by csc :-) new { itemA, itemB, itemC } .ForEach(item => { item.Number = 1; item.Str = "Hello World!"; }); 

注意:

这不像Select因为Select 期望你的函数返回一些东西来转换成另一个列表。

ForEach只允许您为每个项目执行一些操作,而无需进行任何转换/数据操作。

我做了这个,所以我可以在一个更实用的风格编程,我很惊讶,List有一个ForEach,而IEnumerable没有。

把这个放在codeplex项目中

我的转换扩展程序允许您执行以下操作:

 int i = myString.To<int>(); 

在TheSoftwareJedi.com上发布

 public static T To<T>(this IConvertible obj) { return (T)Convert.ChangeType(obj, typeof(T)); } public static T ToOrDefault<T> (this IConvertible obj) { try { return To<T>(obj); } catch { return default(T); } } public static bool ToOrDefault<T> (this IConvertible obj, out T newObj) { try { newObj = To<T>(obj); return true; } catch { newObj = default(T); return false; } } public static T ToOrOther<T> (this IConvertible obj, T other) { try { return To<T>obj); } catch { return other; } } public static bool ToOrOther<T> (this IConvertible obj, out T newObj, T other) { try { newObj = To<T>(obj); return true; } catch { newObj = other; return false; } } public static T ToOrNull<T> (this IConvertible obj) where T : class { try { return To<T>(obj); } catch { return null; } } public static bool ToOrNull<T> (this IConvertible obj, out T newObj) where T : class { try { newObj = To<T>(obj); return true; } catch { newObj = null; return false; } } 

你可以要求默认值(调用空构造函数或者数字“0”),指定一个“默认”值(我称之为“other”),或者请求null(T:class)。 我还提供了静默exception模型,以及一个典型的TryParse模型,它返回一个表示所采取行动的布尔值,并且一个外部参数保存新的值。 所以我们的代码可以做这样的事情

 int i = myString.To<int>(); string a = myInt.ToOrDefault<string>(); //note type inference DateTime d = myString.ToOrOther(DateTime.MAX_VALUE); double d; //note type inference bool didItGiveDefault = myString.ToOrDefault(out d); string s = myDateTime.ToOrNull<string>(); 

我无法将Nullabletypes非常干净地整理成整个事物。 在我扔了毛巾之前,我尝试了大约20分钟。

我有一个loggingexception的扩展方法:

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

它是这样使用的:

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

[抱歉张贴两次; 第二个是更好的devise:-)]

 public static class StringExtensions { /// <summary> /// Parses a string into an Enum /// </summary> /// <typeparam name="T">The type of the Enum</typeparam> /// <param name="value">String value to parse</param> /// <returns>The Enum corresponding to the stringExtensions</returns> public static T EnumParse<T>(this string value) { return StringExtensions.EnumParse<T>(value, false); } public static T EnumParse<T>(this string value, bool ignorecase) { if (value == null) { throw new ArgumentNullException("value"); } value = value.Trim(); if (value.Length == 0) { throw new ArgumentException("Must specify valid information for parsing in the string.", "value"); } Type t = typeof(T); if (!t.IsEnum) { throw new ArgumentException("Type provided must be an Enum.", "T"); } return (T)Enum.Parse(t, value, ignorecase); } } 

用于将stringparsing为Enum。

 public enum TestEnum { Bar, Test } public class Test { public void Test() { TestEnum foo = "Test".EnumParse<TestEnum>(); } } 

信贷给斯科特·多曼

—编辑Codeplex项目—

我曾经问过Scott Dorman他是否会介意我们在Codeplex项目中发布他的代码。 这是我从他那里得到的答复:

感谢SOpost和CodePlex项目的单挑。 我已经提出了你的问题的答案。 是的,这些代码实际上是在CodeProject开放许可证( http://www.codeproject.com/info/cpol10.aspx )下的公共领域。

我对CodePlex项目中包含的这个问题没有任何问题,如果您想将我添加到项目中(用户名是sdorman),我将添加该方法以及其他一些枚举辅助方法。

我觉得这个很有用:

 public static class PaulaBean { private static String paula = "Brillant"; public static String GetPaula<T>(this T obj) { return paula; } } 

您可以在CodePlex上使用它。

DateTimeExtensions

例子:

 DateTime firstDayOfMonth = DateTime.Now.First(); DateTime lastdayOfMonth = DateTime.Now.Last(); DateTime lastFridayInMonth = DateTime.Now.Last(DayOfWeek.Friday); DateTime nextFriday = DateTime.Now.Next(DayOfWeek.Friday); DateTime lunchTime = DateTime.Now.SetTime(11, 30); DateTime noonOnFriday = DateTime.Now.Next(DayOfWeek.Friday).Noon(); DateTime secondMondayOfMonth = DateTime.Now.First(DayOfWeek.Monday).Next(DayOfWeek.Monday).Midnight(); 

gitorious.org/cadenza是我见过的一些最有用的扩展方法的完整库。

这里是我经常使用的演示文稿格式。

 public static string ToTitleCase(this string mText) { if (mText == null) return mText; System.Globalization.CultureInfo cultureInfo = System.Threading.Thread.CurrentThread.CurrentCulture; System.Globalization.TextInfo textInfo = cultureInfo.TextInfo; // TextInfo.ToTitleCase only operates on the string if is all lower case, otherwise it returns the string unchanged. return textInfo.ToTitleCase(mText.ToLower()); } 

这是一个罗马数字的来回。 不经常使用,但可能会得心应手。 用法:

 if ("IV".IsValidRomanNumeral()) { // Do useful stuff with the number 4. } Console.WriteLine("MMMDCCCLXXXVIII".ParseRomanNumeral()); Console.WriteLine(3888.ToRomanNumeralString()); 

来源:

  public static class RomanNumeralExtensions { private const int NumberOfRomanNumeralMaps = 13; private static readonly Dictionary<string, int> romanNumerals = new Dictionary<string, int>(NumberOfRomanNumeralMaps) { { "M", 1000 }, { "CM", 900 }, { "D", 500 }, { "CD", 400 }, { "C", 100 }, { "XC", 90 }, { "L", 50 }, { "XL", 40 }, { "X", 10 }, { "IX", 9 }, { "V", 5 }, { "IV", 4 }, { "I", 1 } }; private static readonly Regex validRomanNumeral = new Regex( "^(?i:(?=[MDCLXVI])((M{0,3})((C[DM])|(D?C{0,3}))" + "?((X[LC])|(L?XX{0,2})|L)?((I[VX])|(V?(II{0,2}))|V)?))$", RegexOptions.Compiled); public static bool IsValidRomanNumeral(this string value) { return validRomanNumeral.IsMatch(value); } public static int ParseRomanNumeral(this string value) { if (value == null) { throw new ArgumentNullException("value"); } value = value.ToUpperInvariant().Trim(); var length = value.Length; if ((length == 0) || !value.IsValidRomanNumeral()) { throw new ArgumentException("Empty or invalid Roman numeral string.", "value"); } var total = 0; var i = length; while (i > 0) { var digit = romanNumerals[value[--i].ToString()]; if (i > 0) { var previousDigit = romanNumerals[value[i - 1].ToString()]; if (previousDigit < digit) { digit -= previousDigit; i--; } } total += digit; } return total; } public static string ToRomanNumeralString(this int value) { const int MinValue = 1; const int MaxValue = 3999; if ((value < MinValue) || (value > MaxValue)) { throw new ArgumentOutOfRangeException("value", value, "Argument out of Roman numeral range."); } const int MaxRomanNumeralLength = 15; var sb = new StringBuilder(MaxRomanNumeralLength); foreach (var pair in romanNumerals) { while (value / pair.Value > 0) { sb.Append(pair.Key); value -= pair.Value; } } return sb.ToString(); } } 

处理尺寸的便捷方法:

 public static class Extensions { public static int K(this int value) { return value * 1024; } public static int M(this int value) { return value * 1024 * 1024; } } public class Program { public void Main() { WSHttpContextBinding serviceMultipleTokenBinding = new WSHttpContextBinding() { MaxBufferPoolSize = 2.M(), // instead of 2097152 MaxReceivedMessageSize = 64.K(), // instead of 65536 }; } } 

对于Winform控件:

 /// <summary> /// Returns whether the function is being executed during design time in Visual Studio. /// </summary> public static bool IsDesignTime(this Control control) { if (LicenseManager.UsageMode == LicenseUsageMode.Designtime) { return true; } if (control.Site != null && control.Site.DesignMode) { return true; } var parent = control.Parent; while (parent != null) { if (parent.Site != null && parent.Site.DesignMode) { return true; } parent = parent.Parent; } return false; } /// <summary> /// Sets the DropDownWidth to ensure that no item's text is cut off. /// </summary> public static void SetDropDownWidth(this ComboBox comboBox) { var g = comboBox.CreateGraphics(); var font = comboBox.Font; float maxWidth = 0; foreach (var item in comboBox.Items) { maxWidth = Math.Max(maxWidth, g.MeasureString(item.ToString(), font).Width); } if (comboBox.Items.Count > comboBox.MaxDropDownItems) { maxWidth += SystemInformation.VerticalScrollBarWidth; } comboBox.DropDownWidth = Math.Max(comboBox.Width, Convert.ToInt32(maxWidth)); } 

IsDesignTime用法:

 public class SomeForm : Form { public SomeForm() { InitializeComponent(); if (this.IsDesignTime()) { return; } // Do something that makes the visual studio crash or hang if we're in design time, // but any other time executes just fine } } 

SetDropdownWidth用法:

 ComboBox cbo = new ComboBox { Width = 50 }; cbo.Items.Add("Short"); cbo.Items.Add("A little longer"); cbo.Items.Add("Holy cow, this is a really, really long item. How in the world will it fit?"); cbo.SetDropDownWidth(); 

我忘了提及,在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项目上使用这个代码是可以的。

移动到C#时,我错过了Visual Basic的With语句 ,所以在这里:

 public static void With<T>(this T obj, Action<T> act) { act(obj); } 

以下是如何在C#中使用它:

 someVeryVeryLonggggVariableName.With(x => { x.Int = 123; x.Str = "Hello"; x.Str2 = " World!"; }); 

节省了很多打字!

比较这个:

 someVeryVeryLonggggVariableName.Int = 123; someVeryVeryLonggggVariableName.Str = "Hello"; someVeryVeryLonggggVariableName.Str2 = " World!"; 

把codeplex项目

Takes a camelCaseWord or PascalCaseWord and "wordifies" it, ie camelCaseWord => camel Case Word

 public static string Wordify( this string camelCaseWord ) { // if the word is all upper, just return it if( !Regex.IsMatch( camelCaseWord, "[az]" ) ) return camelCaseWord; return string.Join( " ", Regex.Split( camelCaseWord, @"(?<!^)(?=[AZ])" ) ); } 

I often use it in conjuction with Capitalize

 public static string Capitalize( this string word ) { return word[0].ToString( ).ToUpper( ) + word.Substring( 1 ); } 

用法示例

 SomeEntityObject entity = DataAccessObject.GetSomeEntityObject( id ); List<PropertyInfo> properties = entity.GetType().GetPublicNonCollectionProperties( ); // wordify the property names to act as column headers for an html table or something List<string> columns = properties.Select( p => p.Name.Capitalize( ).Wordify( ) ).ToList( ); 

Free to use in codeplex project

I found this one helpful

 public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> pSeq) { return pSeq ?? Enumerable.Empty<T>(); } 

It removes the null check in the calling code. You could now do

 MyList.EmptyIfNull().Where(....) 

Convert a double to string formatted using the specified culture:

 public static class ExtensionMethods { public static string ToCurrency(this double value, string cultureName) { CultureInfo currentCulture = new CultureInfo(cultureName); return (string.Format(currentCulture, "{0:C}", value)); } } 

例:

 double test = 154.20; string testString = test.ToCurrency("en-US"); // $154.20 

Below is an extension method that adapts Rick Strahl's code (and the comments too) to stop you having to guess or read the byte order mark of a byte array or text file each time you convert it to a string.

The snippet allows you to simply do:

 byte[] buffer = File.ReadAllBytes(@"C:\file.txt"); string content = buffer.GetString(); 

If you find any bugs please add to the comments. Feel free to include it in the Codeplex project.

 public static class Extensions { /// <summary> /// Converts a byte array to a string, using its byte order mark to convert it to the right encoding. /// Original article: http://www.west-wind.com/WebLog/posts/197245.aspx /// </summary> /// <param name="buffer">An array of bytes to convert</param> /// <returns>The byte as a string.</returns> public static string GetString(this byte[] buffer) { if (buffer == null || buffer.Length == 0) return ""; // Ansi as default Encoding encoding = Encoding.Default; /* EF BB BF UTF-8 FF FE UTF-16 little endian FE FF UTF-16 big endian FF FE 00 00 UTF-32, little endian 00 00 FE FF UTF-32, big-endian */ if (buffer[0] == 0xef && buffer[1] == 0xbb && buffer[2] == 0xbf) encoding = Encoding.UTF8; else if (buffer[0] == 0xfe && buffer[1] == 0xff) encoding = Encoding.Unicode; else if (buffer[0] == 0xfe && buffer[1] == 0xff) encoding = Encoding.BigEndianUnicode; // utf-16be else if (buffer[0] == 0 && buffer[1] == 0 && buffer[2] == 0xfe && buffer[3] == 0xff) encoding = Encoding.UTF32; else if (buffer[0] == 0x2b && buffer[1] == 0x2f && buffer[2] == 0x76) encoding = Encoding.UTF7; using (MemoryStream stream = new MemoryStream()) { stream.Write(buffer, 0, buffer.Length); stream.Seek(0, SeekOrigin.Begin); using (StreamReader reader = new StreamReader(stream, encoding)) { return reader.ReadToEnd(); } } } } 

Here's one I just created today.

 // requires .NET 4 public static TReturn NullOr<TIn, TReturn>(this TIn obj, Func<TIn, TReturn> func, TReturn elseValue = default(TReturn)) where TIn : class { return obj != null ? func(obj) : elseValue; } // versions for CLR 2, which doesn't support optional params public static TReturn NullOr<TIn, TReturn>(this TIn obj, Func<TIn, TReturn> func, TReturn elseValue) where TIn : class { return obj != null ? func(obj) : elseValue; } public static TReturn NullOr<TIn, TReturn>(this TIn obj, Func<TIn, TReturn> func) where TIn : class { return obj != null ? func(obj) : default(TReturn); } 

It lets you do this:

 var lname = thingy.NullOr(t => t.Name).NullOr(n => n.ToLower()); 

which is more fluent and (IMO) easier to read than this:

 var lname = (thingy != null ? thingy.Name : null) != null ? thingy.Name.ToLower() : null; 

"Please mark your answers with an acceptance to put the code in the Codeplex project."

为什么? All the Stuff on this site under CC-by-sa-2.5 , so just put your Extension overflow Project under the same license and you can freely use it.

Anyway, here is a String.Reverse function, based on this question .

 /// <summary> /// Reverse a String /// </summary> /// <param name="input">The string to Reverse</param> /// <returns>The reversed String</returns> public static string Reverse(this string input) { char[] array = input.ToCharArray(); Array.Reverse(array); return new string(array); } 

I got tired of tedious null-checking while pulling values from MySqlDataReader, so:

 public static DateTime? GetNullableDateTime(this MySqlDataReader dr, string fieldName) { DateTime? nullDate = null; return dr.IsDBNull(dr.GetOrdinal(fieldName)) ? nullDate : dr.GetDateTime(fieldName); } public static string GetNullableString(this MySqlDataReader dr, string fieldName) { return dr.IsDBNull(dr.GetOrdinal(fieldName)) ? String.Empty : dr.GetString(fieldName); } public static char? GetNullableChar(this MySqlDataReader dr, string fieldName) { char? nullChar = null; return dr.IsDBNull(dr.GetOrdinal(fieldName)) ? nullChar : dr.GetChar(fieldName); } 

Of course this could be used with any SqlDataReader.


Both hangy and Joe had some good comments on how to do this, and I have since had an opportunity to implement something similar in a different context, so here is another version:

 public static int? GetNullableInt32(this IDataRecord dr, int ordinal) { int? nullInt = null; return dr.IsDBNull(ordinal) ? nullInt : dr.GetInt32(ordinal); } public static int? GetNullableInt32(this IDataRecord dr, string fieldname) { int ordinal = dr.GetOrdinal(fieldname); return dr.GetNullableInt32(ordinal); } public static bool? GetNullableBoolean(this IDataRecord dr, int ordinal) { bool? nullBool = null; return dr.IsDBNull(ordinal) ? nullBool : dr.GetBoolean(ordinal); } public static bool? GetNullableBoolean(this IDataRecord dr, string fieldname) { int ordinal = dr.GetOrdinal(fieldname); return dr.GetNullableBoolean(ordinal); } 

It irritated me that LINQ gives me an OrderBy that takes a class implementing IComparer as an argument, but does not support passing in a simple anonymous comparer function. I rectified that.

This class creates an IComparer from your comparer function…

 /// <summary> /// Creates an <see cref="IComparer{T}"/> instance for the given /// delegate function. /// </summary> internal class ComparerFactory<T> : IComparer<T> { public static IComparer<T> Create(Func<T, T, int> comparison) { return new ComparerFactory<T>(comparison); } private readonly Func<T, T, int> _comparison; private ComparerFactory(Func<T, T, int> comparison) { _comparison = comparison; } #region IComparer<T> Members public int Compare(T x, T y) { return _comparison(x, y); } #endregion } 

…and these extension methods expose my new OrderBy overloads on enumerables. I doubt this works for LINQ to SQL, but it's great for LINQ to Objects.

 public static class EnumerableExtensions { /// <summary> /// Sorts the elements of a sequence in ascending order by using a specified comparison delegate. /// </summary> public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, TKey, int> comparison) { var comparer = ComparerFactory<TKey>.Create(comparison); return source.OrderBy(keySelector, comparer); } /// <summary> /// Sorts the elements of a sequence in descending order by using a specified comparison delegate. /// </summary> public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, TKey, int> comparison) { var comparer = ComparerFactory<TKey>.Create(comparison); return source.OrderByDescending(keySelector, comparer); } } 

You're welcome to put this on codeplex if you like.

This one is for MVC it adds the ability to generate a <label /> tag to the Html variable that is available in every ViewPage . Hopefully it will be of use to others trying to develop similar extensions.

使用:

 <%= Html.Label("LabelId", "ForId", "Text")%> 

输出:

 <label id="LabelId" for="ForId">Text</label> 

码:

 public static class HtmlHelperExtensions { public static string Label(this HtmlHelper Html, string @for, string text) { return Html.Label(null, @for, text); } public static string Label(this HtmlHelper Html, string @for, string text, object htmlAttributes) { return Html.Label(null, @for, text, htmlAttributes); } public static string Label(this HtmlHelper Html, string @for, string text, IDictionary<string, object> htmlAttributes) { return Html.Label(null, @for, text, htmlAttributes); } public static string Label(this HtmlHelper Html, string id, string @for, string text) { return Html.Label(id, @for, text, null); } public static string Label(this HtmlHelper Html, string id, string @for, string text, object htmlAttributes) { return Html.Label(id, @for, text, new RouteValueDictionary(htmlAttributes)); } public static string Label(this HtmlHelper Html, string id, string @for, string text, IDictionary<string, object> htmlAttributes) { TagBuilder tag = new TagBuilder("label"); tag.MergeAttributes(htmlAttributes); if (!string.IsNullOrEmpty(id)) tag.MergeAttribute("id", Html.AttributeEncode(id)); tag.MergeAttribute("for", Html.AttributeEncode(@for)); tag.SetInnerText(Html.Encode(text)); return tag.ToString(TagRenderMode.Normal); } } 

Turn this:

 DbCommand command = connection.CreateCommand(); command.CommandText = "SELECT @param"; DbParameter param = command.CreateParameter(); param.ParameterName = "@param"; param.Value = "Hello World"; command.Parameters.Add(param); 

… into this:

 DbCommand command = connection.CreateCommand("SELECT {0}", "Hello World"); 

… using this extension method:

 using System; using System.Data.Common; using System.Globalization; using System.Reflection; namespace DbExtensions { public static class Db { static readonly Func<DbConnection, DbProviderFactory> getDbProviderFactory; static readonly Func<DbCommandBuilder, int, string> getParameterName; static readonly Func<DbCommandBuilder, int, string> getParameterPlaceholder; static Db() { getDbProviderFactory = (Func<DbConnection, DbProviderFactory>)Delegate.CreateDelegate(typeof(Func<DbConnection, DbProviderFactory>), typeof(DbConnection).GetProperty("DbProviderFactory", BindingFlags.Instance | BindingFlags.NonPublic).GetGetMethod(true)); getParameterName = (Func<DbCommandBuilder, int, string>)Delegate.CreateDelegate(typeof(Func<DbCommandBuilder, int, string>), typeof(DbCommandBuilder).GetMethod("GetParameterName", BindingFlags.Instance | BindingFlags.NonPublic, Type.DefaultBinder, new Type[] { typeof(Int32) }, null)); getParameterPlaceholder = (Func<DbCommandBuilder, int, string>)Delegate.CreateDelegate(typeof(Func<DbCommandBuilder, int, string>), typeof(DbCommandBuilder).GetMethod("GetParameterPlaceholder", BindingFlags.Instance | BindingFlags.NonPublic, Type.DefaultBinder, new Type[] { typeof(Int32) }, null)); } public static DbProviderFactory GetProviderFactory(this DbConnection connection) { return getDbProviderFactory(connection); } public static DbCommand CreateCommand(this DbConnection connection, string commandText, params object[] parameters) { if (connection == null) throw new ArgumentNullException("connection"); return CreateCommandImpl(GetProviderFactory(connection).CreateCommandBuilder(), connection.CreateCommand(), commandText, parameters); } private static DbCommand CreateCommandImpl(DbCommandBuilder commandBuilder, DbCommand command, string commandText, params object[] parameters) { if (commandBuilder == null) throw new ArgumentNullException("commandBuilder"); if (command == null) throw new ArgumentNullException("command"); if (commandText == null) throw new ArgumentNullException("commandText"); if (parameters == null || parameters.Length == 0) { command.CommandText = commandText; return command; } object[] paramPlaceholders = new object[parameters.Length]; for (int i = 0; i < paramPlaceholders.Length; i++) { DbParameter dbParam = command.CreateParameter(); dbParam.ParameterName = getParameterName(commandBuilder, i); dbParam.Value = parameters[i] ?? DBNull.Value; command.Parameters.Add(dbParam); paramPlaceholders[i] = getParameterPlaceholder(commandBuilder, i); } command.CommandText = String.Format(CultureInfo.InvariantCulture, commandText, paramPlaceholders); return command; } } } 

More ADO.NET extension methods: DbExtensions