Які ваші улюблені методи розширення для C #? (codeplex.com/extensionoverflow)


478

Давайте складемо список відповідей, де ви розміщуєте свої чудові та улюблені методи розширення .

Вимога полягає в тому, що повинен бути розміщений повний код, а також приклад та пояснення щодо його використання.

На основі великого інтересу до цієї теми я створив проект із відкритим кодом під назвою 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 ФорматWith зараз впроваджений та випробуваний .

09.11.2008 Другий внесок приєднався до ExtensionOverflow . Ласкаво просимо в чакрит .

09.11.2008 Нам потрібно більше розробників. ;-)

09.11.2008 ThrowIfArgumentIsNull в даний час впроваджений та випробуваний підрозділ на Codeplex.


Тепер перший код зафіксований на сайті Codeplex.
бовіум

На жаль, Ерік зараз все розпочато на кодеплексі. Будь-ласка, приєднайтесь.
бовіум

3
Виглядає досить добре. У мене є коментар щодо називання статичних класів. Назви їх <type> Розширення не дуже інформативно. Наприклад, StringExtensions містить як форматування, так і файли xml. Я думаю, що краще назвати клас з тим, чому ви розширюєте цей тип. Наприклад, UnixDateTimeConversions. Можна обґрунтовано здогадуватися, що він містить методи перетворення в час Unix і з нього. Просто думка!
ecoffey

Перевірте цю URL-адресу, щоб дізнатися більше про методи розширення C # planetofcoders.com/c-extension-methods
Gaurav Agrawal

Відповіді:


232
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....
}

2
Добре це компілюється, якщо ви використовуєте System.Linq;
Рю

11
Можливо, "EqualsAnyOf" було б кращим ім'ям, ніж "В"?
Том Бушелл

10
Я не впевнений, що мені це подобається - мені подобається стислість In, але, можливо, IsInбуло б краще.
Вінстон Сміт

50
Використовуючи той самий метод Contains: (новий [] {1, 2, 3}). Містить (a)
Макс Торо

4
Я також подумав про In<T>(...)це і виявив, що це найкорисніший метод розширення за межами стандартної бібліотеки. Але я суперечу з назвою In. Ім'я методу повинно описувати те, що він робить, але Inне робить цього. Я це назвав IsAnyOf<T>(...), але, мабуть, IsIn<T>(...)був би і адекватним.
JBSnorro

160

У моєму проекті 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 до 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 - тут знадобиться занадто багато часу, щоб пояснити, але шукати його.


1
Це мило! Ви повинні розмістити його на Google Code або CodePlex, щоб я могла вам надіслати кілька патчів :-) Обіцяю, що він буде читабельним :-P
chakrit

3
@bovium: Ви вже можете бачити код. Перейдіть за посиланням у першому реченні - повне джерело є.
Джон Скіт

1
@bovium: Я вважаю за краще зробити це сам, розмістивши його на code.google.com та керуючи проектом сам, якщо ви не заперечуєте. Очевидно, ви маєте ліцензію на те, щоб розмістити його на Codeplex, якщо ви зберігатимете відповідну атрибуцію, але я скоріше розберуся незабаром, якщо ви не впадаєте у відчай :)
Джон Скіт

1
@Jon Skeet Його ставлять під ліцензію MIT безкоштовно для всіх. Комерційний або відкритий код. Чому б не об'єднати зусилля та зробити бібліотеку методів розширення для громадськості.
бовіум

1
Просто тому, що в цій бібліотеці я роблю багато інших фрагментів. Ви можете взяти копію всього цього для свого проекту, але я б краще зберегти один примірник у своєму власному проекті.
Джон Скіт

147

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") ?

Для більш читаного імені спробуйте одну з таких пропозицій:

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");

..


11
Це, звичайно, коротко - але буде нечитабельним для будь-яких нових членів вашої команди.
Джон Скіт

3
Я думаю, що читабельність має більше значення в схемі грандіознішого коду, ніж кілька скорочень, які можна швидко переглянути / запитати.
чакрит

6
Особисто мені хотілося б окремий об’єкт Форматтер, який BCL міг би проаналізувати шаблон одного разу та повторно використовувати його. Це збільшить читабельність та продуктивність. Я запитав команду BCL - ми побачимо ...
Джон Скіт

3
Це метод розширення, звичайно, це буде нечитабельним для нових членів команди. Я думав, що це ідея цього дотепного матеріалу? Як інакше нові члени будуть знати, наскільки ми розумні?
MarkJ

17
Гаразд ... Я просто почав це робити і пішов з. З - так ви отримаєте "Це {0}". С ("тест"), і це дуже легко читається і має сенс. FYI
klkitchens

89

Це будь-яка користь?

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!");

це імітує пітони random.choice (seq) функції. приємно.
Дарен Томас

6
Пару: я рекомендую OneOfприйняти будь-яку IList<T> . Тоді ви завжди також можете мати перевантаження, яка бере paramsаргумент і просто передає це в IList<T>перевантаження. Я дав відповідь (прямо внизу зараз) NextBoolметодом, подібним до вашого CoinToss, але з перевантаженням, яке приймає probabilityпараметр (що робити, якщо я хочу, щоб щось траплялося в 75% часу?). Крім того, лише вибір нитки: ваш приклад код буде кидати, NullReferenceExceptionоскільки randніколи не ініціалізується.
Дан Дао

3
+1 Мені це дуже подобається, але я вважаю CoinTossза краще реалізовувати, rng.NextDouble() < .5тому що внутрішньо .Next(int)зроблено за допомогою, .NextDouble()щоб ви зберегли кастинг, * та чек.
Lasse Espeholt

76
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))
{
  // ....
}

19
Мені це подобається, але я намагаюся вирішити, чи правильно зробити межі перевірки включно на мінімальне значення, але виключно на максимальне значення. Цікаво, чи було б це заплутано. 5.Відмінність (5,10) - це правда, але 5.Біж (1,5) - хибна. Навіть не впевнений, що допоможе супутник у межах методу. Тис?
Стів Хінер

12
Хіба назва "IsBet između" не мала б більше сенсу? Також можливо зробити IsBetweenInclusive та IsBetweenExclusive. Не маю ідеї, яку брати за замовчуванням.
fretje

2
@Steve: має більше сенсу, якби це було продовженням дати.
Джоел Куехорн

16
Для мене між ними випливає: 5.Between (5,10) повертає false, а 10.Between (5,10) також повертає false. Це для мене просто природно.
Олексій Бараноський

3
Мені здається, що багато людей мають різні ідеї щодо природного. Через це, ймовірно, слід чітко вказати, що використовується (тобто включно проти ексклюзиву), оскільки це може бути дуже простим джерелом помилок.
Девід Міані

58

Спосіб розширення:

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);

15
Було б краще, як цей IList <T>

21
Просто використовуйте ініціалізатор колекцій =>var list = new List<int>{5,4,8,4,2};
Арніс Лапса

Чому б просто не викликати Список <T> .AddRange (IEnumerable <T> collection) у межах вашого методу?
Раухоц

8
@Will: Насправді, найкраще було б прийняти ICollection<T>; тоді він також може бути використаний, наприклад, LinkedList<T>і HashSet<T>не лише індексованими колекціями.
Дан Дао

2
Відредаговано, щоб дозволити коваріацію до pre.net.net 4.0
BlueRaja - Danny Pflughoeft

55

Це неодмінно покладіть це на проект кодексу.

Серіалізація / десеріалізація об'єктів у 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.
    }
}

8
Мені б ToXml()сподобалося зателефонувати першому (як ToString())
Джей Базузі

1
Вибачте ОП, якщо він навмисно написав це таким чином, але використання MemoryStreams AND XmlReader / XmlWriter було надмірним. Класи StringReader і StringWriter ідеально підходять для цієї операції.
Портман

2
Остерігайтеся, це не є безпечним для ниток. Ви обов'язково повинні синхронізувати ваш доступ до словника статичних серіалізаторів.
Янн Шварц

2
@Yann, @T, Це набагато простіше, якщо просто додати атрибут "статичний потік". Тоді буде створено новий кеш на кожну нитку. Не потрібно синхронізації.
Френк Крюгер

1
@Jonathan C Дікінсон: З документів MSDN тут msdn.microsoft.com/en-us/library/… випливає, що конструктор, який використовується (новий XmlSerializer (тип)), не має проблеми з витоком пам'яті. То, можливо, код кешування не потрібен?
slolife

46

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 просто дозволяє виконати щось для кожного з елементів без будь-яких перетворень / маніпулювання даними.

Я зробив це, щоб я міг програмувати у більш функціональному стилі, і я був здивований, що у списку є ForEach, а IEnumerable цього не робить.

Помістіть це в проект codeplex


13
Публікація про те, чому в безлічі <T> розширеннях LINQ не входить формат ForEach: stackoverflow.com/questions/317874/…
Neil

13
Рекомендую прочитати це перед використанням методу: blogs.msdn.com/ericlippert/archive/2009/05/18/…
jpbochi

2
@jpbochi: Це просто демагогія Microsoft
абатищев

1
@abatishchev І ваш коментар - це лише упередження щодо Microsoft. Це не визнає жодного слова, написаного Еріком. Аргументи когось не вважаються дійсними або недійсними лише через компанію, в якій він працює.
jpbochi

1
До речі, дозвольте зрозуміти одну точку. Я не сказав, що ви не повинні використовувати цей метод розширення ForEach. Я щойно сказав, що ви повинні розглянути моменти, які викрив Ерік, перш ніж вирішити, використовувати його чи ні. Я прочитав його і вирішив не використовувати. Ви можете робити все, що завгодно, зі своїм кодом.
jpbochi

43

Мої розширення для конверсій, які дозволяють вам робити:

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, яка повертає буль, що вказує на вжиті дії, а параметр out містить у собі нове значення. Тож наш код може робити такі речі

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 хвилин, перш ніж кинути рушник.


64
Особисто я не прихильник коду, який намагаюся визначити результат. Спробуйте / catch слід використовувати для помилок, які трапляються поза передбачуваною логікою, IMO. hmmmmm
Pure.Krome

Якби я не хотів, щоб ти використовував цей код, я б його не розміщував! :)
TheSoftwareJedi

Нарешті щось невидиме. Мені це подобається. :)
Арніс Лапса

8
Вам слід принаймні змінити цей пункт "catch", щоб уловлювати лише ті винятки, які може змінити ChangeType (), коли він не може "перетворити" посилання. Я думаю, ви б не хотіли, щоб якісь OutOfMemoryException, ExecutionEngineException, ThreadAbortException або подібні трактувалися як помилка перетворення. Ці речі інакше будуть досить важко відслідковувати помилки.
Крістіан.К

2
Я вважаю, ToOrNullмає таку саму поведінку, як і ToOrDefault(тобто, якщо ви зателефонуєте ToOrDefaultна тип посилання з невдалою конверсією, він повернеться null). Але що ще важливіше, мені це видається надмірним, оскільки він var s = myObject as stringвиконує те саме, що й var s = myObject.ToOrNull<string>()- але без потенційного необхідності ловити InvalidCastException. Я щось пропускаю?
Дан Дао

43

У мене є метод розширення для реєстрації винятків:

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

І використовується так:

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

[вибачте за публікацію двічі; другий краще розроблений :-)]


2
Чи слід читати загальнодоступний статичний журнал недійсностей (цей виняток obj) {} можливо?
Chris S

Я думаю, що це добре для винятків BCL або сторонніх розробників, але якщо ви робите власні типи винятків, ви можете розмістити вхід у базовий клас виключень. Таким чином, вам не потрібно пам’ятати, щоб викликати Журнал ().
si618

38
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), я додам цей метод плюс кілька додаткових допоміжних методів.


Цей сценарій синтаксичного розбору придумується весь час ... треба помістити це в мою
війку

Нічого собі, я писав методи, щоб зіставити рядки до переліків (щойно почав використовувати .NET). Дякую, це абсолютно допоможе!
Кевін

4
Ви також можете розглянути можливість іменування цього ToEnum <> (), оскільки воно відбувається після об'єкта.
Ніл

Зауважте, що Enum.TryParse <T> додано до Net 4.0 - blogs.msdn.com/bclteam
Dan Diplo

1
Я не думаю, що цей метод повинен використовувати Trim. Обрізання вводу повинно бути відповідальним за абонента.
CodesInChaos

32

Я вважаю це досить корисним:

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

Ви можете використовувати його на CodePlex.


2
Чи може хтось бути добрим, щоб пояснити це менш обдарованим з нас?
jpbochi

хахаха Просто прочитайте статтю (коментар Джоеля вище) - правда смішна, але перебуваючи в майже одній і тій же човні (на приймаючому кінці, а не в кінці Паули), це лише смішно озираючись назад! Після того, як підрядник був залучений до роботи над проектом, я був призначений / ведучий розробник - вона не знаходилась під моїм безпосереднім контролем, але була призначена робота з мого списку робочих груп. Боси похвалили її як геніальну (навіть найнявши її знову пізніше як Деві Ведучу!) Їм ніколи не приснилося, що кожен написаний або розроблений код не приніс його у виробництво, і моя команда повинна бути повністю переписана з нуля!
Wolf5370

31

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();

5
Я б запропонував перейменувати "SetTime" на "WithTime", оскільки він насправді не встановлює його у існуючому значенні. Хороший інакше, хоча.
Джон Скіт

28
DateTime.Now.First () - перше що? Це видно лише з зразкового коду.
mackenir

2
Дуже хороший. Але погодьтеся, що імена могли бути набагато кращими.
бовіум

DateTime.Now.First буде достатньо зрозумілим в Intellisense, якщо метод добре задокументований.
Райан Лунді

29

gitorious.org/cadenza - це повна бібліотека деяких найкорисніших методів розширення, які я бачив.


12 досить основних методів розширення. Я трохи недоохоплений моно-скелями.
mackenir

(Я говорю про випущену версію, а не про ту, для якої потрібно використовувати джерело-контроль)
mackenir

28

Ось такий, який я часто використовую для форматування презентації.

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());
}

Ну, обробка виключень Pokemon приховує такі проблеми, як ThreadAbortException тощо. Будь ласка, впіймайте щось конкретне.
JBRWilkinson

28

Ось до-і-з для римських цифр. Не часто використовується, але може бути зручним. Використання:

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();
        }
    }

Це нагадує мені про Python PEP 313, яка була першоквітневий жарт включити римська цифра літерали в Python: python.org/dev/peps/pep-0313
торіальную

25

Зручний спосіб вирішити розміри:

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
        };
    }
}

На мою думку, це дійсно поганий стиль кодування. Натомість слід використовувати константи, а не заплутану логіку.
xxbbcc

24

Для управління 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 ...


1
Як уже згадувалося, це лише для WinForms. Він може працювати з WPF, але є проблеми (описані в коментарі про WPF за адресою msdn.microsoft.com/en-us/library/… ). Найкраще рішення для WPF, яке я знайшов, описане в geekswithblogs.net/lbugnion/archive/2009/09/05/… (хоча, оскільки це статична властивість, він насправді не працює як метод розширення.)
scobi

23

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 .


Мені це теж подобається, у Джона це є у своєму, і я використовую щось подібне від Umbrella, могло б стояти, щоб скинути частину "ArgumentIs".
cfeduke

Ага! це також метод розширення
kewl

3
Якщо ви використовуєте конструктор ArgumentNullException із лише 1 рядковим аргументом, цей аргумент повинен бути лише назвою параметра, а не повідомленням про помилку. Отже, ваш код повинен виглядати так: якщо (obj == null) киньте новий ArgumentNullException (parameterName);
Томмі Карльєр

Я б використовував default(T)для цього і видаляв вимогу до класу.
Joel Coehoorn

1
@Joel: Значення за замовчуванням для нативних типів є законними аргументами частіше, ніж нульовими. Перевірка проти нуля має для мене більше сенсу, ніж перевірка за замовчуванням. Звичайно, я просто узагальнюю всю ідею, кажучи Require.ThatArgument(input != null)або Require.ThatArgument(personId > 0). Це не потребує набагато більше коду, він набагато гнучкіший, і він читається чудово. У мене є додаткові зміни, які виконують функції, коли ви хочете налаштувати повідомлення про помилку або саме виняток.
StriplingWarrior

22

Я пропускаю оператор Visual Basic's With при переході до 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!";

поставити в проект кодексу


4
Лише здогадка, але подумайте, що станеться, якщо ваш T - структура.
Раухоц

5
Я також використовую синтаксис ініціалізатора властивостей c # 3.0, коли це можливо, щоб досягти однакового результату.
Стів

3
@chakrit, ось приклад. Він застосовується лише при створенні об'єкта Кнопка n = нова кнопка {Name = "Button1", Width = 100, Height = 20, Enabled = true};
Стів

1
Це було б корисно, коли у вас є багато подій, щоб підключити, оскільки синтаксис ініціалізатора властивостей C # не підтримує події.
Гейб

1
це також корисно поза ініціалізаторами властивостей, тому що ви можете використовувати їх лише під час створення нового об'єкта. це розширення може працювати над раніше створеними об'єктами.
Брейді Моріц

18

Бере собі camelCaseWord або PascalCaseWord і «зміцнює» його, тобто camelCaseWord => Word Word Case

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( );

Безкоштовно використовувати у проекті кодексу


Агрегат з великого капіталу є досить поганим для продуктивності, оскільки створює багато рядкових екземплярів. Чому б замість цього не використовувати word.Substring (1)?
Томас Левеск

17

Я вважаю це корисним

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

Це видаляє нульову перевірку в коді виклику. Тепер ви могли це зробити

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

Так, якщо хтось забув "Null Object Pattern", цей метод корисний для того, щоб закріпити його. Колекція ніколи не повинна бути нульовою.
Павло Ходек

16

Перетворити відформатований подвійний на рядок за допомогою вказаної культури:

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

13
Вам слід скористатися десятковою грошовою одиницею, інакше ви отримаєте питання округлення
Ендрю Буллок

Як щодо використання Enum в параметрі замість простого рядка
Rulas

15

Нижче наведено метод розширення, який адаптує код Ріка Штраля (та коментарі також), щоб перешкодити вам здогадуватися чи читати позначку порядку байти масиву байтів або текстового файлу кожного разу, коли ви перетворюєте його в рядок.

Фрагмент дозволяє вам просто робити:

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();
            }
        }
    }
}

Дуже корисний метод, але я не думаю, що це має бути і метод розширення.
Поп Каталін

Якщо ви пишете текстовий редактор, це, ймовірно, вимагає методу розширення, але я згоден, більшість часу це, мабуть, не більше ніж статичний приватний метод
Chris S

15

Ось я тільки що створив сьогодні.

// 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;

1
Що робити, якщо я хочу thingy.NullOr(t => t.Count), де Countінт? Ви повинні повернутися, default(TReturn)а не нульові, тому вам не знадобиться classобмеження, і воно буде працювати і для типів цінності
Томас Левеск

2
TIn повинен бути класом, інакше весь цей метод розширення не має сенсу (типи значень не можуть бути нульовими). І ваш приклад із t.Count працює з описаним вище способом розширення. Не могли б ви поглянути другий?
Скобі

@Scott: це корисний метод для поширеної проблеми. Однак, я вважаю TReturn elseValue = default(TReturn), доступний лише для .NET 4.0? У мене є 3,5 SP1, і я ніколи не бачив цієї конструкції (ні в мого компілятора немає). Я просто перемістив це всередину методу. Одне питання, однак, полягає в тому, що бокс типу нульового об'єкта для використання методом дає несподіваний результат (0 проти очікуваної нулі).
Джим Шуберт

@Jim: default(T)ключове слово існує з VS2005, але я думаю, що параметри за замовчуванням - це нова. NET 4. Найпростішим способом її вирішення повинно бути два варіанти, той, який бере парам, і той, який цього не робить. Я оновлю відповідь, щоб вона була сумісною з CLR 2.0. Щодо боксу - ось у чому справа default. Це будуть 0-ініціалізовані дані для типу значення та null для всіх типів посилань. TReturn значення значення повинен залишатися без коробки до кінця функції.
Скобі

@Scott: Моє запитання стосувалося параметра за замовчуванням, який я бачив лише у таких динамічних мовах, як Ruby. Моя думка щодо змінних типів полягає в тому, що повернення x.Valueмає повернути нульове значення (якщо, наприклад,int? було null) або значення, якщо воно int?має значення. Повернення, 0коли int? x = nullйого передано та встановлено в поле для об'єкта, є випадковим випадком. Я бачив подібні перевірки змінних типів у бібліотеках, таких як вільне нібернат та лінфу (я думаю) для цього конкретного випадку, що дозволяє скинути обмеження класу, як було запропоновано раніше.
Джим Шуберт

14

"Будь ласка, позначте свої відповіді з прийняттям, щоб ввести код у проект 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);
}

Чи String вже не реалізує IEnumerable <char>? Тому вам просто потрібно буде повернути новий String (input.Reverse ());
Ієн Галлоуей

Реалізація за допомогою StringBuilder має бути швидшою.
CodesInChaos

1
@CodeInChaos порівняльного аналізу в stackoverflow.com/questions/228038 вимірюється , що StringBuilder повільніше.
Майкл Штум

Ти правий. Схоже, вимоги безпеки потоку (можливо, щоб забезпечити незмінність рядка, повернутого ToString) дуже повільно знижують StringBuilder.
CodesInChaos

2
Сподіваємось, ви не зіткнетесь із жодними сурогатами чи поєднаннями персонажів.
dalle

14

Я втомився від виснажливої ​​перевірки нуля під час витягування значень з 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);
}

2
Це також має працювати як метод розширення для IDataReader.
хань

2
Власне, зробіть "цей" параметр типу IDataRecord для максимальної сумісності. У моїй версії цього, у мене є перевантаження, яка приймає порядковий номер, який викликає версія fieldName. Зберігає "GetOrdinal" з подальшим пошуком за назвою.
Джоель Мюллер

Є належна реалізація, яка може мати справу з будь-яким типом значень: rabdullin.com/journal/2008/12/6/…
Rinat

Завдяки Ринат, я на самому ділі отримав це до одного універсального методу - див stackoverflow.com/questions/303287
Адам Lassek

Усі ці методи, здається, не потрібні, оскільки ви можете використовувати asключове слово, щоб отримати значення у читача, враховуючи нуль. Якщо ви комбінуєте ??оператор об'єднання нуля з оператором as, ви навіть можете мати ненулеве значення за замовчуванням для переходу безпосередньо до типу значення. Див stackoverflow.com/questions/746767 / ...
stevehipwell

14

Мене це дратувало тим, що 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 до SQL, але це чудово для LINQ для об'єктів.

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);
    }
}

Ви можете розмістити це на кодеплексі, якщо хочете.


13

Цей варіант призначений для 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);
    }
}

Ознайомтеся з MvcContrib.FluentHtml
Арніс Лапса

Це, мабуть, слід дублювати замість Literal.
Марк Херд

12

Поверніть це:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.