Какие ваши любимые методы расширения для 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 FormatWith теперь реализован и протестирован .

09.11.2008 Второй участник присоединился к ExtensionOverflow . добро пожаловать в чакрит .

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

09.11.2008 ThrowIfArgumentIsNull в настоящее время реализовано и модульное тестирование на Codeplex.


Теперь первый код размещен на сайте Codeplex.
Bovium

Эрик, к сожалению, все запущено сейчас на codeplex. Пожалуйста, присоединяйтесь в любом случае.
Bovium

3
Выглядит довольно хорошо У меня есть комментарий о присвоении имен статическим классам. Называть их <тип> расширениями не очень информативно. Например, StringExtensions содержит как форматирование, так и xml. Я думаю, что лучше назвать класс с тем, почему вы расширяете этот тип. Например UnixDateTimeConversions. Вы можете разумно предположить, что он содержит методы для преобразования во время Unix и обратно. Просто мысль!
ecoffey

Проверьте этот URL для получения дополнительной информации о методах расширения C # planetofcoders.com/c-extension-methods
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" будет лучшим названием, чем "In"?
Том Бушелл

10
Я не уверен, что мне это нравится - мне нравится краткость In, но, возможно IsIn, будет лучше.
Уинстон Смит

50
Использование того же метода Contains: (new [] {1, 2, 3}). Contains (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 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 - это займет слишком много времени, чтобы объяснить здесь, но искать его.


1
Это мило! Вы должны поставить его на Google Code или CodePlex, чтобы я мог отправить вам несколько исправлений :-) Я обещаю, что он будет читабельным :-P
chakrit

3
@bovium: Вы уже можете видеть код. Перейдите по ссылке в первом предложении - полный источник есть.
Джон Скит

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

1
@ Джон Скит. Его положили под лицензией MIT бесплатно для всех. Коммерчески или с открытым исходным кодом. Почему бы не объединить усилия и не сделать библиотеку методов расширения для общественности.
Бовиум

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

147

Строка. Формат ярлыка:

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
Лично я хотел бы отдельный объект Formatter, который BCL мог бы проанализировать образец один раз и повторно использовать. Это повысит читабельность и производительность. Я спросил команду BCL - посмотрим ...
Джон Скит

3
Это метод расширения, конечно, он будет нечитаем для новых членов команды. Я думал, что это была идея с этим остроумным материалом? Как еще новые члены узнают, насколько мы умны?
MarkJ

17
Хорошо ... Я просто пошел, чтобы применить это к действию, и пошел с .With - так вы получите "Это {0}". С ("test"), и это очень читабельно и имеет смысл. К вашему сведению
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 принять . Тогда вы всегда можете также иметь перегрузку , которая принимает ARG и просто передает , что в перегрузку. Я дал ответ (прямо внизу прямо сейчас) с помощью метода, аналогичного вашему , но с перегрузкой, которая принимает параметр (что, если я хочу, чтобы что-то происходило в 75% случаев?). Кроме того, просто придирки: ваш пример кода будет выбрасывать, так как никогда не инициализируется. IList<T>paramsIList<T>NextBoolCoinTossprobabilityNullReferenceExceptionrand
Дан Тао

3
+1 Мне это очень нравится, но я предпочитаю CoinTossреализовывать с помощью, rng.NextDouble() < .5потому что внутренне .Next(int)сделано с помощью, .NextDouble()чтобы вы могли сохранить приведение, * и проверку.
Лассе Эспехолт

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) неверно. Даже не уверен, что метод компаньона внутри поможет. Thougts?
Стив Хинер

12
Разве имя IsBetween не имеет смысла? Также возможно сделать IsBetweenInclusive и IsBetweenExclusive. Не знаю, какой взять по умолчанию, хотя.
fretje

2
@Steve: имеет больше смысла, если бы это было расширение даты и времени.
Джоэл Коухорн

16
Для меня между подразумевается: 5. Между (5,10) возвращает ложь, и 10. Между (5,10) также возвращает ложь. Это просто естественно для меня.
Алекс Бараноски

3
Мне кажется, что у многих людей разные идеи относительно того, что естественно. Из-за этого, вероятно, следует четко указать, что используется (т.е. Inclusive vs Exclusive), поскольку это может быть очень простым источником ошибок.
Дэвид Миани

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};
Арнис Лапса

Почему бы просто не вызвать List <T> .AddRange (IEnumerable <T> collection) в вашем методе?
Раухотц

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

2
Отредактировано, чтобы разрешить ковариацию в pre-.net 4.0
BlueRaja - Дэнни Пфлюгофт

55

Обязательно внесите это в проект 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.
    }
}

8
Я был бы соблазн назвать первый ToXml()(как ToString())
Джей Базузи

1
Извиняюсь перед ФП, если он намеренно написал это таким образом, но использование MemoryStreams AND XmlReader / XmlWriter было излишним. Класс StringReader и StringWriter идеально подходят для этой операции.
Портман

2
Осторожно, это не потокобезопасно. Вы обязательно должны синхронизировать свой доступ к словарю статических сериализаторов.
Ян Шварц

2
@Yann, @T, намного проще, если вы просто добавите атрибут "static static". Затем будет создан новый кэш для каждого потока. Нет необходимости в синхронизации.
Фрэнк Крюгер

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 просто позволяет вам выполнить что-то для каждого из элементов без каких-либо преобразований / манипуляций с данными.

Я сделал это, чтобы я мог программировать в более функциональном стиле, и я был удивлен, что в List есть ForEach, а в IEnumerable нет.

Поместите это в проект codeplex


13
Пост о том, почему расширения LINQ IEnumerable <T> не включают ForEach: stackoverflow.com/questions/317874/…
Нил

13
Я рекомендую прочитать это перед использованием метода: blogs.msdn.com/ericlippert/archive/2009/05/18/…
jpbochi

2
@jpbochi: Это просто демагогия Microsoft
abatishchev 22.10.10

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, которая возвращает логическое значение, указывающее предпринятые действия, и выходной параметр содержит новое значение. Так что наш код может делать такие вещи

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
Лично я не фанат кода, который пытается / ловит, чтобы определить результат. Try / catch следует использовать для ошибок, которые происходят за пределами предполагаемой логики, IMO. хммммм
Pure.Krome

Если бы я не хотел, чтобы вы использовали код, я бы его не опубликовал! :)
TheSoftwareJedi

Наконец-то что-то невидимое. Мне это нравится. :)
Арнис Лапса

8
Вы должны по крайней мере изменить это предложение «catch», чтобы перехватывать только те исключения, которые вызовет ChangeType (), когда он не может «преобразовать» ссылку. Я думаю, вы не хотели бы, чтобы какие-либо OutOfMemoryException, ExecutionEngineException, ThreadAbortException или тому подобное рассматривались как ошибка преобразования. Эти вещи в противном случае будет довольно сложно отследить ошибки.
Christian.K

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-й лучше разработан :-)]


2
Стоит ли читать открытый статический журнал void (это исключение obj) {} может быть?
Крис С

Я думаю, что это хорошо для исключений BCL или сторонних производителей, но если вы прокручиваете свои собственные типы исключений, вы можете поместить запись в базовый класс исключений. Таким образом, вы не должны забывать вызывать Log ().
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), я добавлю этот метод плюс некоторые дополнительные вспомогательные методы enum.


Этот сценарий синтаксического анализа встречается все время ... должен поместить это в мою
библиотеку

Вау, я писал методы для отображения строк в перечисления (только начал использовать .NET). Спасибо, это абсолютно поможет!
Кевин

4
Вы также можете рассмотреть возможность присвоения имени этому ToEnum <> (), так как он идет после объекта.
Нил

Обратите внимание, что Enum.TryParse <T> был добавлен в Net 4.0 - blogs.msdn.com/bclteam
Дэн

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

хахаха Просто прочитайте статью (комментарий Джоэля выше) - забавно, правда, но, находясь почти в одной лодке (в конце приема, а не в конце Паулы), это только смешно, оглядываясь назад! Однажды меня привлекли подрядчика для работы над проектом, над которым я работал дизайнером / ведущим разработчиком - она ​​не находилась под моим непосредственным контролем, но была назначена на работу из рабочего списка моих команд. Боссы похвалили ее за то, что она была блестящей (даже нанять ее позже, как Dev Lead!). Их никогда не осенило, что каждый кусок кода, который она написала или спроектировала, не попал в производство, и моя команда должна была полностью переписать его с нуля!
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 () - сначала что? Это видно только из примера кода.
Маккенир

2
Очень хорошо. Но согласитесь, что имена могут быть намного лучше.
Бовиум

DateTime.Now.First будет достаточно понятным в Intellisense, если метод хорошо документирован.
Райан Ланди

29

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


12 довольно базовых методов расширения. Я немного не в восторге от монокамен.
Маккенир

(Я говорю о выпущенной версии, а не той, которую вам нужно использовать для контроля
версий

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 Controls:

/// <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 :)
Pure.Krome

3
Если вы используете конструктор ArgumentNullException только с одним строковым аргументом, этот аргумент должен быть просто именем параметра, а не сообщением об ошибке. Таким образом, ваш код должен выглядеть следующим образом: if (obj == null) генерировать новое ArgumentNullException (parameterName);
Томми Carlier

Я бы использовал default(T)для этого и удалить требование класса.
Джоэл Кохорн

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

22

Я скучаю по выражению 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


4
Просто предположение, но подумайте, что произойдет, если ваш T - это структура.
Раухотц

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

3
@chakrit, вот пример. Применяется только при создании объекта. Button n = new Button {Name = "Button1", Width = 100, Height = 20, Enabled = true};
Стив

1
Это было бы полезно, когда вам нужно подключить много событий, потому что синтаксис инициализатора свойств C # не поддерживает события.
Гейб

1
это также полезно вне инициализаторов свойств, потому что вы можете использовать их только при создании нового объекта. это расширение может работать с ранее созданными объектами.
Брейди Мориц

18

Принимает 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


Aggregate in Capitalize очень плохо влияет на производительность, поскольку создает много строковых экземпляров. Почему бы не использовать 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), где Countint? Вы должны возвращать, default(TReturn)а не ноль, таким образом, вам не понадобится classограничение, и оно будет работать и для типов значений
Томас Левеск

2
TIn должен быть классом, иначе весь этот метод расширения не имеет смысла (типы значений не могут быть нулевыми). И ваш пример с t.Count работает с вышеуказанным методом расширения. Не могли бы вы взглянуть еще раз?
scobi 1.10.10

@ Скотт: это полезный метод для решения общей проблемы. Тем не менее, я считаю, TReturn elseValue = default(TReturn)что доступен только для .NET 4.0? У меня 3.5 SP1, и я никогда не видел эту конструкцию (ни у меня нет моего компилятора). Я просто переместил это внутрь метода. Одна проблема, однако, заключается в том, что объединение типа NULL в объект для использования с методом дает неожиданный результат (0 против ожидаемого нуля).
Джим Шуберт

@Jim: default(T)ключевое слово существует с VS2005, но я думаю, что параметры по умолчанию - это новая функция .NET 4. Самый простой способ обойти это - иметь два варианта: один, который принимает параметр, а другой - нет. Я обновлю ответ, чтобы быть совместимым с CLR 2.0. Что касается бокса - в этом все дело default. Это будут 0-инициализированные данные для типа значения и нуль для всех ссылочных типов. TReturn типа значения должен оставаться распакованным на протяжении всей функции.
scobi

@Scott: Мой вопрос был о параметре по умолчанию, который я видел только в динамических языках, таких как Ruby. Моя точка зрения относительно типов, допускающих значение NULL, заключается в том, что возвращаемое значение x.Valueдолжно возвращать значение NULL (если, например, int?было NULL) или значение, если оно int?имеет значение. Возвращение, 0когда int? x = nullоно передано и помещено в объект, является странным случаем. Я видел подобные проверки для обнуляемых типов в библиотеках, таких как беглый nhibernate и linfu (я думаю) для этого конкретного случая, позволяя вам снять ограничение класса, как предлагалось ранее.
Джим Шуберт

14

«Пожалуйста, отметьте свои ответы принятием, чтобы поместить код в проект Codeplex».

Почему? Все вещи на этом сайте под CC-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>? Так что вам просто нужно вернуть return String (input.Reverse ());
Иан Галлоуэй

Реализация с использованием StringBuilder должна быть быстрее.
CodesInChaos

1
@CodeInChaos Тестирование в stackoverflow.com/questions/228038 показало, что StringBuilder медленнее.
Майкл Стум

Вы правы. Похоже, что требования безопасности потока (возможно, для обеспечения неизменности строки, возвращаемой ToString) сильно замедляют StringBuilder.
CodesInChaos

2
Надеюсь, вы не встретите никаких суррогатов или комбинирующих персонажей.
Далле

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.
hangy

2
На самом деле, сделайте параметр "this" типа IDataRecord для максимальной совместимости. В моей версии этого у меня есть перегрузка, которая принимает порядковый номер, который вызывает версия fieldName. Сохраняет «GetOrdinal» с последующим поиском по имени.
Джоэл Мюллер

Существует правильная реализация, которая может работать с любым типом значения: rabdullin.com/journal/2008/12/6/…
Ринат Абдуллин,

Благодаря Ринату, я на самом деле свел это к одному универсальному методу - см. Stackoverflow.com/questions/303287
Адам Лассек

Все эти методы кажутся ненужными, так как вы можете использовать asключевое слово, чтобы получить значение от читателя с нулевым значением. Если вы объедините ??оператор слияния null с оператором 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 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);
    }
}

Вы можете поместить это в кодекс, если хотите.


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.