Какие ваши любимые методы расширения для C#? (Codeplex.com/extensionoverflow)
Давайте составим список ответов, где вы разместите свои превосходные и любимые методы расширения.
Требование заключается в том, что должен быть опубликован полный код, а также пример и объяснение того, как его использовать.
Основываясь на высоком интересе к этой теме, я настроил проект с открытым исходным кодом, который называется extensionoverflow в Codeplex.
Пожалуйста, отметьте ваши ответы принятием, чтобы поместить код в проект 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 Нам нужно больше разработчиков.;-)
09.11.2008 ThrowIfArgumentIsNull в настоящее время реализовано и модульное тестирование на Codeplex.
150 ответов
public static bool In<T>(this T source, params T[] list)
{
if(null==source) throw new ArgumentNullException("source");
return list.Contains(source);
}
Позволяет мне заменить:
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 (полный исходный код доступен здесь - я не буду повторять это здесь). Мои любимые, некоторые из которых включают другие классы (например, диапазоны):
Дата и время - в основном для юнит-тестов. Не уверен, что я буду использовать их в производстве:)
var birthday = 19.June(1976);
var workingDay = 7.Hours() + 30.Minutes();
Диапазон и шаг - огромное спасибо Марку Гравеллу за его работу оператора, которая сделала это возможным:
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 применяется к анонимным типам (или другим типам с соответствующими свойствами):
// <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 - это займет слишком много времени, чтобы объяснить здесь, но искать его.
Строка. Формат ярлыка:
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")
?
Для более удобочитаемого имени, попробуйте одно из следующих предложений:
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);
}
Метод применяется для всех типов и позволяет добавлять в список ряд элементов в качестве параметров.
Пример:
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 для 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" для чисел) при неудаче, указать значение "по умолчанию" (я называю это "другое") или запросить ноль (где T: класс). Я также предоставил как модели молчаливых исключений, так и типичную модель 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>();
Я не мог заставить Nullable типы втиснуть все это очень чисто. Я пытался минут 20, прежде чем бросил полотенце.
У меня есть метод расширения для регистрации исключений:
public static void Log(this Exception obj)
{
//your logging logic here
}
И это используется так:
try
{
//Your stuff here
}
catch(Exception ex)
{
ex.Log();
}
[извините за публикацию дважды; 2-й лучше разработан:-)]
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);
}
}
Полезно для разбора строки в Enum.
public enum TestEnum
{
Bar,
Test
}
public class Test
{
public void Test()
{
TestEnum foo = "Test".EnumParse<TestEnum>();
}
}
Кредит идет к Скотту Дорману
--- Редактировать для проекта Codeplex ---
Я спросил Скотта Дормана, не возражает ли он, чтобы мы опубликовали его код в проекте Codeplex. Вот ответ, который я получил от него:
Спасибо за хедз-ап на пост SO и проект CodePlex. Я проголосовал за ваш ответ на вопрос. Да, код в настоящее время находится в свободном доступе в рамках открытой лицензии CodeProject ( http://www.codeproject.com/info/cpol10.aspx).
У меня нет проблем с тем, чтобы это было включено в проект CodePlex, и если вы хотите добавить меня в проект (имя пользователя - sdorman), я добавлю этот метод плюс некоторые дополнительные вспомогательные методы enum.
Я нахожу это довольно полезным:
public static class PaulaBean
{
private static String paula = "Brillant";
public static String GetPaula<T>(this T obj) {
return paula;
}
}
Вы можете использовать его на CodePlex.
http://www.codeplex.com/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();
http://www.gitorious.org/cadenza - это полная библиотека некоторых наиболее полезных методов расширения, которые я видел.
Вот для и от римских цифр. Не часто используется, но может быть удобно. Использование:
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 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());
}
Удобный способ справиться с размерами:
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.
Я скучаю по выражению With в Visual Basic при переходе на C#, так что вот оно:
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
Принимает camelCaseWord или PascalCaseWord и "словоизирует" его, т.е. camelCaseWord => верблюд Case Case Word
public static string Wordify( this string camelCaseWord )
{
// if the word is all upper, just return it
if( !Regex.IsMatch( camelCaseWord, "[a-z]" ) )
return camelCaseWord;
return string.Join( " ", Regex.Split( camelCaseWord, @"(?<!^)(?=[A-Z])" ) );
}
Я часто использую его в сочетании с 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( );
Бесплатное использование в проекте codeplex
Я нашел это полезным
public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> pSeq)
{
return pSeq ?? Enumerable.Empty<T>();
}
Это удаляет нулевую проверку в коде вызова. Теперь вы можете сделать
MyList.EmptyIfNull().Where(....)
Преобразование двойного в строковое форматирование с использованием указанной культуры:
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
Вот тот, который я только что создал сегодня.
// 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); }
Это позволяет вам сделать это:
var lname = thingy.NullOr(t => t.Name).NullOr(n => n.ToLower());
который более свободно и (IMO) легче читать, чем это:
var lname = (thingy != null ? thingy.Name : null) != null
? thingy.Name.ToLower() : null;
Ниже приведен метод расширения, который адаптирует код Рика Страля (и комментарии), чтобы вам не приходилось угадывать или читать метку порядка байтов массива байтов или текстового файла каждый раз, когда вы конвертируете его в строку.
Фрагмент позволяет вам просто сделать:
byte[] buffer = File.ReadAllBytes(@"C:\file.txt");
string content = buffer.GetString();
Если вы обнаружите какие-либо ошибки, пожалуйста, добавьте в комментарии. Не стесняйтесь включать его в проект Codeplex.
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();
}
}
}
}
Меня раздражало, что LINQ дает мне OrderBy, который принимает класс, реализующий IComparer в качестве аргумента, но не поддерживает передачу простой анонимной функции сравнения. Я исправил это.
Этот класс создает IComparer из вашей функции сравнения...
/// <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
}
... и эти методы расширения раскрывают мои новые перегрузки OrderBy для перечислимых объектов. Я сомневаюсь, что это работает для LINQ to SQL, но отлично подходит для 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);
}
}
Вы можете поместить это в кодекс, если хотите.
"Пожалуйста, отметьте свои ответы принятием, чтобы поместить код в проект Codeplex".
Зачем? Все вещи на этом сайте под CC-by-sa-2.5, так что просто поместите свой проект переполнения расширений под той же лицензией, и вы можете свободно использовать его.
В любом случае, здесь есть функция String.Reverse, основанная на этом вопросе.
/// <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);
}
Я устал от утомительной проверки нуля при извлечении значений из MySqlDataReader, поэтому:
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);
}
Конечно, это может быть использовано с любым SqlDataReader.
У обоих и Джо были хорошие комментарии о том, как это сделать, и с тех пор у меня была возможность реализовать нечто подобное в другом контексте, так что вот еще одна версия:
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);
}
Этот для MVC добавляет возможность генерировать <label />
тег к Html
переменная, которая доступна в каждом ViewPage
, Надеемся, что это будет полезно для других, пытающихся разрабатывать подобные расширения.
Использование:
<%= 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);
}
}
Включите это:
DbCommand command = connection.CreateCommand();
command.CommandText = "SELECT @param";
DbParameter param = command.CreateParameter();
param.ParameterName = "@param";
param.Value = "Hello World";
command.Parameters.Add(param);
... в это:
DbCommand command = connection.CreateCommand("SELECT {0}", "Hello World");
... используя этот метод расширения:
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;
}
}
}
Дополнительные методы расширения ADO.NET: DbExtensions