2009-06-05 2 views
70

Я начинаю по-настоящему любить методы расширения ... Мне было интересно, если кто-то ее наткнулся на человека, который действительно взорвал их мысли или просто нашел умным.Какое лучшее или наиболее интересное использование методов расширения вы видели?

Пример я написал сегодня:

редакцией из-за комментариями других пользователей:

public static IEnumerable<int> To(this int fromNumber, int toNumber) { 
    while (fromNumber < toNumber) { 
     yield return fromNumber; 
     fromNumber++; 
    } 
} 

Это позволяет цикл должен быть записан в виде петли Еогеасп:

foreach (int x in 0.To(16)) { 
    Console.WriteLine(Math.Pow(2, x).ToString()); 
} 

Я не могу дождаться, чтобы увидеть другие примеры! Наслаждайтесь!

+1

Отлично! Я люблю это. –

+19

Ваш метод - это в основном повторная реализация Enumerable.Range (http://msdn.microsoft.com/en-us/library/system.linq.enumerable.range.aspx). Разница заключается в том, что Range принимает начало и счет, а ваш занимает от и до. Ваш также идет вразрез с обычной ограничивающей практикой (<), включая high-end (<=). Наконец, он может идти назад, но на практике это редко бывает необходимо. –

+1

+1 Хмм, я не знал, что существует, спасибо за ссылку! Вы правы насчет ограничивающих ... это был всего лишь пример, который я собрал в течение нескольких минут - второй, который вы пытаетесь сделать «0.To (myList.Count)», вы получите исключение. – Pwninstein

ответ

1

Мне нравится this one. Это вариант метода String.Split, который позволяет использовать escape-символ для подавления разделения, когда разделенный символ предназначен для фактической строки.

18

Полное решение слишком велико для размещения здесь, но я написал ряд методов расширения, которые позволят вам легко преобразовать DataTable в CSV.

public static String ToCSV(this DataTable dataTable) 
{ 
    return dataTable.ToCSV(null, COMMA, true); 
} 

public static String ToCSV(this DataTable dataTable, String qualifier) 
{ 
    return dataTable.ToCSV(qualifier, COMMA, true); 
} 

private static String ToCSV(this DataTable dataTable, String qualifier, String delimiter, Boolean includeColumnNames) 
{ 
    if (dataTable == null) return null; 

    if (qualifier == delimiter) 
    { 
     throw new InvalidOperationException(
      "The qualifier and the delimiter are identical. This will cause the CSV to have collisions that might result in data being parsed incorrectly by another program."); 
    } 

    var sbCSV = new StringBuilder(); 

    var delimiterToUse = delimiter ?? COMMA; 

    if (includeColumnNames) 
     sbCSV.AppendLine(dataTable.Columns.GetHeaderLine(qualifier, delimiterToUse)); 

    foreach (DataRow row in dataTable.Rows) 
    { 
     sbCSV.AppendLine(row.ToCSVLine(qualifier, delimiterToUse)); 
    } 

    return sbCSV.Length > 0 ? sbCSV.ToString() : null; 
} 

private static String ToCSVLine(this DataRow dataRow, String qualifier, String delimiter) 
{ 
    var colCount = dataRow.Table.Columns.Count; 
    var rowValues = new String[colCount]; 

    for (var i = 0; i < colCount; i++) 
    { 
     rowValues[i] = dataRow[i].Qualify(qualifier); 
    } 

    return String.Join(delimiter, rowValues); 
} 

private static String GetHeaderLine(this DataColumnCollection columns, String qualifier, String delimiter) 
{ 
    var colCount = columns.Count; 
    var colNames = new String[colCount]; 

    for (var i = 0; i < colCount; i++) 
    { 
     colNames[i] = columns[i].ColumnName.Qualify(qualifier); 
    } 

    return String.Join(delimiter, colNames); 
} 

private static String Qualify(this Object target, String qualifier) 
{ 
    return qualifier + target + qualifier; 
} 

В конце концов, вы могли бы назвать это так:

someDataTable.ToCSV(); //Plain old CSV 
someDataTable.ToCSV("\""); //Double quote qualifier 
someDataTable.ToCSV("\"", "\t"); //Tab delimited 
+0

На самом деле я написал целый набор методов расширения как перегрузки, которые позволят вам пройти в пользовательский класс, который определяет такие вещи, как форматирование, имена столбцов и т. Д. .. Это было просто слишком много, чтобы включить в этот пост. – Josh

12

Ну это не совсем умный, но я изменил ---- методы OrDefault, чтобы вы могли указать пункт по умолчанию встроенного в вместо проверки на нуль в коде:

public static T SingleOrDefault<T> (this IEnumerable<T> source, 
            Func<T, bool> action, T theDefault) 
    { 
     T item = source.SingleOrDefault<T>(action); 

     if (item != null) 
      return item; 

     return theDefault; 
    } 

Его невероятно простой, но на самом деле помогает очистить эти пустые чеки. Лучше всего использовать, когда ваш пользовательский интерфейс ожидает список элементов X, например, турнирной системы или игровых слотов, и вы хотите отобразить «пустые места».

Использование:

return jediList.SingleOrDefault( 
       j => j.LightsaberColor == "Orange", 
       new Jedi() { LightsaberColor = "Orange", Name = "DarthNobody"); 
+0

Ницца, мне всегда было интересно, почему это не включало эту перегрузку для SingleOrDefault и FirstOrDefault, хорошая инициатива по ее добавлению! – rmoore

+0

Я сделал нечто похожее, хотя я использовал Func вместо T по умолчанию. – Svish

+3

Обратите внимание, что это не будет работать корректно для типов с недействительными значениями. Встроенные расширения SingleOrDefault возвращают значение по умолчанию (T), когда элемент не найден, и это будет только null для ссылочных типов или типов с нулевым значением. – LukeH

11

Вот один я взломал вместе, так что не стесняйтесь, чтобы выбрать в нем отверстия. Он принимает (упорядоченный) список целых чисел и возвращает список строк смежных диапазонов. например: пример

public static IEnumerable<string> IntRanges(this IEnumerable<int> numbers) 
{ 
    int rangeStart = 0; 
    int previous = 0; 

    if (!numbers.Any()) 
     yield break; 

    rangeStart = previous = numbers.FirstOrDefault(); 

    foreach (int n in numbers.Skip(1)) 
    { 
     if (n - previous > 1) // sequence break - yield a sequence 
     { 
      if (previous > rangeStart) 
      { 
       yield return string.Format("{0}-{1}", rangeStart, previous); 
      } 
      else 
      { 
       yield return rangeStart.ToString(); 
      } 
      rangeStart = n; 
     } 
     previous = n; 
    } 

    if (previous > rangeStart) 
    { 
     yield return string.Format("{0}-{1}", rangeStart, previous); 
    } 
    else 
    { 
     yield return rangeStart.ToString(); 
    } 
} 

Использование::

1,2,3,7,10,11,12 --> "1-3","7","10-12" 

Функция (в статическом классе)

this.WeekDescription = string.Join(",", from.WeekPattern.WeekPatternToInts().IntRanges().ToArray()); 

Этот код используется для преобразования данных из приложения расписаний DailyWTF достойные. WeekPattern - это битмаска, хранящаяся в строке «0011011100 ...». WeekPatternToInts() преобразует его в IEnumerable <int>, в этом случае [3,4,6,7,8], который становится «3-4,6-8». Он предоставляет пользователю компактное описание академических недельных диапазонов, на которых происходит лекция.

+0

Я не могу придумать немедленного использования для этого, но это удивительно, тем не менее :) – Josh

+0

Спасибо! Я добавил пример, показывающий, как я его использую. – geofftnz

+0

Зачем нужны ненужные действия, такие как ненужное присвоение previous = n, проверка на первый раз на каждой итерации и форматирование одного номера? – okutane

11

Два, которые мне нравятся, - это InsertWhere <T> и RemoveWhere <T> Методы расширения, которые я написал. Работа с ObservableCollections в WPF и Silverlight Мне часто приходится изменять упорядоченные списки без их повторного создания. Эти методы позволяют мне вставлять и удалять в соответствии с предоставленным Func.OrderBy() не требует повторного вызова.

/// <summary> 
    /// Removes all items from the provided <paramref name="list"/> that match the<paramref name="predicate"/> expression. 
    /// </summary> 
    /// <typeparam name="T">The class type of the list items.</typeparam> 
    /// <param name="list">The list to remove items from.</param> 
    /// <param name="predicate">The predicate expression to test against.</param> 
    public static void RemoveWhere<T>(this IList<T> list, Func<T, bool> predicate) 
    { 
     T[] copy = new T[] { }; 
     Array.Resize(ref copy, list.Count); 
     list.CopyTo(copy, 0); 

     for (int i = copy.Length - 1; i >= 0; i--) 
     { 
      if (predicate(copy[i])) 
      { 
       list.RemoveAt(i); 
      } 
     } 
    } 

    /// <summary> 
    /// Inserts an Item into a list at the first place that the <paramref name="predicate"/> expression fails. If it is true in all cases, then the item is appended to the end of the list. 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    /// <param name="list"></param> 
    /// <param name="obj"></param> 
    /// <param name="predicate">The sepcified function that determines when the <paramref name="obj"/> should be added. </param> 
    public static void InsertWhere<T>(this IList<T> list, T obj, Func<T, bool> predicate) 
    { 
     for (int i = 0; i < list.Count; i++) 
     { 
      // When the function first fails it inserts the obj paramiter. 
      // For example, in a list myList of ordered Int32's {1,2,3,4,5,10,12} 
      // Calling myList.InsertWhere(8, x => 8 > x) inserts 8 once the list item becomes greater then or equal to it. 
      if(!predicate(list[i])) 
      { 
       list.Insert(i, obj); 
       return; 
      } 
     } 

     list.Add(obj); 
    } 

Edit:
Talljoe сделаны значительные улучшения в RemoveWhere/RemoveAll, что я поспешно построил. При использовании элементов ~ 3mill, удаляющих каждую третью, новая версия занимает всего ~ 50 миллисекунд (менее 10, если она может вызвать List.RemoveAll!), В отличие от нескольких секунд RemoveWhere (я устал ждать ее.)

Вот его значительно улучшенная версия, еще раз спасибо!

public static void RemoveAll<T>(this IList<T> instance, Predicate<T> predicate) 
    { 
     if (instance == null) 
      throw new ArgumentNullException("instance"); 
     if (predicate == null) 
      throw new ArgumentNullException("predicate"); 
     if (instance is T[]) 
      throw new NotSupportedException(); 

     var list = instance as List<T>; 
     if (list != null) 
     { 
      list.RemoveAll(predicate); 
      return; 
     } 

     int writeIndex = 0; 
     for (int readIndex = 0; readIndex < instance.Count; readIndex++) 
     { 
      var item = instance[readIndex]; 
      if (predicate(item)) continue; 

      if (readIndex != writeIndex) 
      { 
       instance[writeIndex] = item; 
      } 
      ++writeIndex; 
     } 

     if (writeIndex != instance.Count) 
     { 
      for (int deleteIndex = instance.Count - 1; deleteIndex >= writeIndex; --deleteIndex) 
      { 
       instance.RemoveAt(deleteIndex); 
      } 
     } 
    } 
+2

RemoveWhere несколько неэффективен из-за изменения всей памяти при удалении элемента (если IList не является LinkedList). Я создал измененный вариант здесь: http://pastebin.com/f20e73b4e Различия: 1) Переименовано в «RemoveAll» для соответствия версии . 2) Список вызовов , если применимо (более эффективно, чем даже моя версия 3). Используйте два индекса, чтобы перейти к списку и выполнить замену значений на месте. 4) Обращайтесь к случаю, когда кто-то передает массив (я думаю, что я предпочитаю бросать исключение, но я хотел бы сделать это до изменения массива - упражнение для читателя). – Talljoe

+0

Я даже не заметил Список .RemoveAll, я просто предположил, что все расширения расширили IList , у которого его нет. Спасибо, что указали! К сожалению, я не могу его использовать, поскольку ObservableCollection просто наследуется от IList. Одно замечание: ваш чек для пункта №2 приведет к переполнению стека, Func в Predicate не может быть преобразован в Predicate. Вторая половина из вас значительно быстрее, чем моя, но я определенно собираюсь это реализовать. Если вы не возражаете, я отредактирую свой пост с обновленной версией. – rmoore

+0

Идите прямо вперед. Интересно, что бесконечная рекурсия, я был уверен, что я ее протестировал, и это сработало. * shrug * Это заставит его работать: list.RemoveAll (t => предикат (t)); – Talljoe

1

метод выдвижения на междунар декодировать битовую маску с указанием дней (с первым днем ​​недели будучи понедельник в данном случае) к перечислению DAYOFWEEK перечислений:

public static IEnumerable<DayOfWeek> Days(this int dayMask) 
{ 
    if ((dayMask & 1) > 0) yield return DayOfWeek.Monday; 
    if ((dayMask & 2) > 0) yield return DayOfWeek.Tuesday; 
    if ((dayMask & 4) > 0) yield return DayOfWeek.Wednesday; 
    if ((dayMask & 8) > 0) yield return DayOfWeek.Thursday; 
    if ((dayMask & 16) > 0) yield return DayOfWeek.Friday; 
    if ((dayMask & 32) > 0) yield return DayOfWeek.Saturday; 
    if ((dayMask & 64) > 0) yield return DayOfWeek.Sunday; 
} 
+0

Почему вы используете доход здесь? Мне любопытно, как это работает ... Если у вас есть понедельник и пятница, т. Е. 0010001, как ваш dayMask, каков будет эффект использования доходности возврата и возврата? –

+0

ah - Я вижу - он в основном начинается там, где он остался в битовой маске, когда вы перебираете ее. Понял. –

9

Пара методов расширения для преобразования базового-36 строки в целые числа (!):

public static int ToBase10(this string base36) 
{ 
    if (string.IsNullOrEmpty(base36)) 
     return 0; 
    int value = 0; 
    foreach (var c in base36.Trim()) 
    { 
     value = value * 36 + c.ToBase10(); 
    } 
    return value; 
} 

public static int ToBase10(this char c) 
{ 
    if (c >= '0' && c <= '9') 
     return c - '0'; 
    c = char.ToUpper(c); 
    if (c >= 'A' && c <= 'Z') 
     return c - 'A' + 10; 
    return 0; 
} 

(Некоторые гений решил, что лучший способ хранения чисел в базе данных было кодировать их в строки Decimals занимают слишком много места Hex лучше, но оленья кожа использовать символы.. GZ. Поэтому, очевидно, вы расширяете базу-16 до базы-36!)

+2

Хм, нужна функция импорта, чтобы взять ваш пример и сразу же опубликовать его на ежедневном wtf. (Хотя я недавно консультировался с клиентом, который создавал и использовал пользовательские подсказки в своем db. Создал guid, отключил конец и добавил временную метку. Серьезно wtf.) – rmoore

+0

Я использовал базовые номера 36, но только тогда, когда мне было нужно для поддержки большого адресного пространства человекочитаемых идентификаторов, которые должны были вписываться в 4-байтовое поле в формате сообщений древнего (и немодифицируемого) систем. Я все еще думаю, что это оправданный случай использования, хотя реальным решением было выбросить древнюю систему. –

+0

Всегда есть base64 :) Я не уверен, что процесс принятия решений был в приложении, с которым я имел дело. Мне сказали, что приложение фактически использует плоские файлы для хранения данных, и чтобы сделать его многопользовательской системой, они просто взрывают все в базу данных для сохранения и обновления локального хранилища файлов в init. – geofftnz

10

У меня есть различные методы расширения, которые полезны для сброса объектов в файл журнала. Например, вот мой словарь debugify (у меня есть это в список, Datatable, парам массив и т.д.):

public static string Debugify<TKey, TValue>(this Dictionary<TKey, TValue> dictionary) { 
    string Result = ""; 

    if (dictionary.Count > 0) { 
     StringBuilder ResultBuilder = new StringBuilder(); 

     int Counter = 0; 
     foreach (KeyValuePair<TKey, TValue> Entry in dictionary) { 
      Counter++; 
      ResultBuilder.AppendFormat("{0}: {1}, ", Entry.Key, Entry.Value); 
      if (Counter % 10 == 0) ResultBuilder.AppendLine(); 
     } 
     Result = ResultBuilder.ToString(); 
    } 
    return Result; 
} 

И вот один за DbParameterCollection (полезно для сброса базы данных вызовов в лог-файл):

public static string Debugify(this DbParameterCollection parameters) { 
    List<string> ParameterValuesList = new List<string>(); 

    foreach (DbParameter Parameter in parameters) { 
     string ParameterName, ParameterValue; 
     ParameterName = Parameter.ParameterName; 

     if (Parameter.Direction == ParameterDirection.ReturnValue) 
      continue; 

     if (Parameter.Value == null || Parameter.Value.Equals(DBNull.Value)) 
      ParameterValue = "NULL"; 
     else 
     { 
      switch (Parameter.DbType) 
      { 
       case DbType.String: 
       case DbType.Date: 
       case DbType.DateTime: 
       case DbType.Guid: 
       case DbType.Xml: 
        ParameterValue 
         = "'" + Parameter 
           .Value 
           .ToString() 
           .Replace(Environment.NewLine, "") 
           .Left(80, "...") + "'"; // Left... is another nice one 
        break; 

       default: 
        ParameterValue = Parameter.Value.ToString(); 
        break; 
      } 

      if (Parameter.Direction != ParameterDirection.Input) 
       ParameterValue += " " + Parameter.Direction.ToString(); 
     } 

     ParameterValuesList.Add(string.Format("{0}={1}", ParameterName, ParameterValue)); 
    } 

    return string.Join(", ", ParameterValuesList.ToArray()); 
} 

Пример результата:

Log.DebugFormat("EXEC {0} {1}", procName, params.Debugify); 
// EXEC spProcedure @intID=5, @nvName='Michael Haren', @intRefID=11 OUTPUT 

Обратите внимание, что если вы звоните этот после ваши вызовы БД, вы также получите параметры вывода. Я вызываю это на строке, которая включает имя SP, поэтому я могу скопировать/вставить вызов в SSMS для отладки.


Это делает мои файлы журналов красивыми и легко генерируемыми без прерывания моего кода.

1

Это один создает массив с одним элементом добавлены в самом начале:

public static T[] Prepend<T>(this T[] array, T item) 
{ 
    T[] result = new T[array.Length + 1]; 
    result[0] = item; 
    Array.Copy(array, 0, result, 1, array.Length); 
    return result; 
} 

string[] some = new string[] { "foo", "bar" }; 
... 
some = some.Prepend("baz"); 

И это один помогает мне, когда мне нужно, чтобы преобразовать некоторое выражение это квадрат:

public static double Sq(this double arg) 
{ 
    return arg * arg; 
} 

(x - x0).Sq() + (y - y0).Sq() + (z - z0).Sq() 
+3

Yikes! Приоритет в массиве - это * такая * плохая идея, концептуально. Будьте уверены, что вы хотите/нуждаетесь в этом ... Создание метода расширения позволяет легко попасть в ловушку заполнения большого массива, добавив большой набор значений в первоначально пустой (или небольшой) массив, создавая свежий временная копия каждого промежуточного массива в этом процессе! Лично я бы этого не сделал. (То же самое касается массива Append, если у вас есть это.) – peSHIr

+1

Я уверен, что мне это нужно. Это используется кодом, в котором массивы широко используются, и их модификация происходит редко. – okutane

+0

Я согласен, что это то, что вы должны использовать с осторожностью. Возможно, вы можете включить перегрузку, которая принимает несколько элементов для добавления, чтобы избежать вызова вашего метода в циклах. –

1

Вот еще один Я написал:

public static class StringExtensions 
    { 
     /// <summary> 
     /// Returns a Subset string starting at the specified start index and ending and the specified end 
     /// index. 
     /// </summary> 
     /// <param name="s">The string to retrieve the subset from.</param> 
     /// <param name="startIndex">The specified start index for the subset.</param> 
     /// <param name="endIndex">The specified end index for the subset.</param> 
     /// <returns>A Subset string starting at the specified start index and ending and the specified end 
     /// index.</returns> 
     public static string Subsetstring(this string s, int startIndex, int endIndex) 
     { 
      if (startIndex < 0) throw new ArgumentOutOfRangeException("startIndex", "Must be positive."); 
      if (endIndex < 0) throw new ArgumentOutOfRangeException("endIndex", "Must be positive."); 
      if (startIndex > endIndex) throw new ArgumentOutOfRangeException("endIndex", "Must be >= startIndex."); 
      return s.Substring(startIndex, (endIndex - startIndex)); 
     } 

     /// <summary> 
     /// Finds the specified Start Text and the End Text in this string instance, and returns a string 
     /// containing all the text starting from startText, to the begining of endText. (endText is not 
     /// included.) 
     /// </summary> 
     /// <param name="s">The string to retrieve the subset from.</param> 
     /// <param name="startText">The Start Text to begin the Subset from.</param> 
     /// <param name="endText">The End Text to where the Subset goes to.</param> 
     /// <param name="ignoreCase">Whether or not to ignore case when comparing startText/endText to the string.</param> 
     /// <returns>A string containing all the text starting from startText, to the begining of endText.</returns> 
     public static string Subsetstring(this string s, string startText, string endText, bool ignoreCase) 
     { 
      if (string.IsNullOrEmpty(startText)) throw new ArgumentNullException("startText", "Must be filled."); 
      if (string.IsNullOrEmpty(endText)) throw new ArgumentNullException("endText", "Must be filled."); 
      string temp = s; 
      if (ignoreCase) 
      { 
       temp = s.ToUpperInvariant(); 
       startText = startText.ToUpperInvariant(); 
       endText = endText.ToUpperInvariant(); 
      } 
      int start = temp.IndexOf(startText); 
      int end = temp.IndexOf(endText, start); 
      return Subsetstring(s, start, end); 
     } 
    } 

Мотивация, стоящая за этим, была простой. Это всегда приводило меня в порядок, как встроенный метод Substring принимал startindex и длину как параметры. ВСЕГДА полезно сделать startindex и endindex. Так, я свернул моя:

Использование:

 string s = "This is a tester for my cool extension method!!"; 
     s = s.Subsetstring("tester", "cool",true); 

Причина мне пришлось использовать Subsetstring потому, что перегрузка подстроки уже принимает два Интс. Если у кого-то есть лучшее имя, пожалуйста, дайте мне знать!

+0

Я не могу понять, почему я этого не сделал сам. +1 –

+0

Возможно, вы могли бы использовать такое имя, как SubstringBetween или даже просто Between. –

+4

@peSHlr: Все хорошо, если вы хотите отредактировать сообщение, но на самом деле ИЗМЕНЕНИЕ кода, потому что вы думаете, что это лучшее исключение, я думаю, что это немного. Я не вернусь, но я думаю, что это слишком далеко. – BFree

0

String.format не должен быть статическим. Поэтому я использую метод расширения под названием Frmt:

<Extension()> Public Function frmt(ByVal format As String, 
            ByVal ParamArray args() As Object) As String 
    If format Is Nothing Then Throw New ArgumentNullException("format") 
    Return String.Format(format, args) 
End Function 

Когда я хочу, чтобы прочитать или написать номер в поток байтов без построения двоичного писателя (технически вы не должны изменять необработанный поток после того, как вы имеете обернул его с писателем):

<Extension()> Public Function Bytes(ByVal n As ULong, 
            ByVal byteOrder As ByteOrder, 
            Optional ByVal size As Integer = 8) As Byte() 
    Dim data As New List(Of Byte) 
    Do Until data.Count >= size 
     data.Add(CByte(n And CULng(&HFF))) 
     n >>= 8 
    Loop 
    Select Case byteOrder 
     Case ByteOrder.BigEndian 
      Return data.ToArray.reversed 
     Case ByteOrder.LittleEndian 
      Return data.ToArray 
     Case Else 
      Throw New ArgumentException("Unrecognized byte order.") 
    End Select 
End Function 
<Extension()> Public Function ToULong(ByVal data As IEnumerable(Of Byte), 
             ByVal byteOrder As ByteOrder) As ULong 
    If data Is Nothing Then Throw New ArgumentNullException("data") 
    Dim val As ULong 
    Select Case byteOrder 
     Case ByteOrder.LittleEndian 
      data = data.Reverse 
     Case ByteOrder.BigEndian 
      'no change required 
     Case Else 
      Throw New ArgumentException("Unrecognized byte order.") 
    End Select 
    For Each b In data 
     val <<= 8 
     val = val Or b 
    Next b 
    Return val 
End Function 
18

Это тот, который получал некоторую игру от меня в последнее время:

public static IDisposable Tag(this HtmlHelper html, string tagName) 
{ 
    if (html == null) 
     throw new ArgumentNullException("html"); 

    Action<string> a = tag => html.Write(String.Format(tag, tagName)); 
    a("<{0}>"); 
    return new Memento(() => a("</{0}>")); 
} 

Используется как:

using (Html.Tag("ul")) 
{ 
    this.Model.ForEach(item => using(Html.Tag("li")) Html.Write(item)); 
    using(Html.Tag("li")) Html.Write("new"); 
} 

Memento представляет собой удобный класс:

public sealed class Memento : IDisposable 
{ 
    private bool Disposed { get; set; } 
    private Action Action { get; set; } 

    public Memento(Action action) 
    { 
     if (action == null) 
      throw new ArgumentNullException("action"); 

     Action = action; 
    } 

    void IDisposable.Dispose() 
    { 
     if (Disposed) 
      throw new ObjectDisposedException("Memento"); 

     Disposed = true; 
     Action(); 
    } 
} 

И для завершения зависимостей:

public static void Write(this HtmlHelper html, string content) 
{ 
    if (html == null) 
     throw new ArgumentNullException("html"); 

    html.ViewContext.HttpContext.Response.Write(content); 
} 
+0

Это хорошо! (Не знаю, почему кто-то запустил его) Может быть, пример не имеет смысла для тех, кто еще не в ASP.NET MVC :) – DSO

+0

Приятный шаблон здесь. Благодарю. +1 –

+0

Очень круто, спасибо за помощь с моим расширением тоже кстати +1 – rmoore

1

круто, также любя Extensions!

вот несколько.

Это один получит последнюю дату в месяц:

<System.Runtime.CompilerServices.Extension()> _ 
    Public Function GetLastMonthDay(ByVal Source As DateTime) As DateTime 
     Dim CurrentMonth As Integer = Source.Month 
     Dim MonthCounter As Integer = Source.Month 
     Dim LastDay As DateTime 
     Dim DateCounter As DateTime = Source 

     LastDay = Source 

     Do While MonthCounter = CurrentMonth 
      DateCounter = DateCounter.AddDays(1) 
      MonthCounter = DateCounter.Month 

      If MonthCounter = CurrentMonth Then 
       LastDay = DateCounter 
      End If 
     Loop 

     Return LastDay 
    End Function 

эти два грим отражение немного легче:

<System.Runtime.CompilerServices.Extension()> _ 
    Public Function GetPropertyValue(Of ValueType)(ByVal Source As Object, ByVal PropertyName As String) As ValueType 
     Dim pInfo As System.Reflection.PropertyInfo 

     pInfo = Source.GetType.GetProperty(PropertyName) 

     If pInfo Is Nothing Then 
      Throw New Exception("Property " & PropertyName & " does not exists for object of type " & Source.GetType.Name) 
     Else 
      Return pInfo.GetValue(Source, Nothing) 
     End If 
    End Function 

    <System.Runtime.CompilerServices.Extension()> _ 
    Public Function GetPropertyType(ByVal Source As Object, ByVal PropertyName As String) As Type 
     Dim pInfo As System.Reflection.PropertyInfo 

     pInfo = Source.GetType.GetProperty(PropertyName) 

     If pInfo Is Nothing Then 
      Throw New Exception("Property " & PropertyName & " does not exists for object of type " & Source.GetType.Name) 
     Else 
      Return pInfo.PropertyType 
     End If 
    End Function 
+1

Вы можете разделить это на два отдельных ответа. Это так! –

+1

... Эта реализация GetLastMonthDay ужасна! Одна строка: return source.AddMonths (1) .AddDays (- (source.Day + 1)); – Task

0

Это одна сдвигает последовательность, так что вы получите данный товар первым , Я использовал его, например, чтобы взять день недели и сдвинуть его так, чтобы первый день в последовательности был первым днем ​​недели для текущей культуры.

/// <summary> 
    /// Shifts a sequence so that the given <paramref name="item"/> becomes the first. 
    /// Uses the specified equality <paramref name="comparer"/> to find the item. 
    /// </summary> 
    /// <typeparam name="TSource">Type of elements in <paramref name="source"/>.</typeparam> 
    /// <param name="source">Sequence of elements.</param> 
    /// <param name="item">Item which will become the first.</param> 
    /// <param name="comparer">Used to find the first item.</param> 
    /// <returns>A shifted sequence. For example Shift({1,2,3,4,5,6}, 3) would become {3,4,5,6,1,2}. </returns> 
    public static IEnumerable<TSource> Shift<TSource>(this IEnumerable<TSource> source, TSource item, IEqualityComparer<TSource> comparer) 
    { 
     var queue = new Queue<TSource>(); 
     bool found = false; 

     foreach (TSource e in source) 
     { 
      if (!found && comparer.Equals(item, e)) 
       found = true; 

      if (found) 
       yield return e; 
      else 
       queue.Enqueue(e); 
     } 

     while (queue.Count > 0) 
      yield return queue.Dequeue(); 
    } 


    /// <summary> 
    /// Shifts a sequence so that the given item becomes the first. 
    /// Uses the default equality comparer to find the item. 
    /// </summary> 
    /// <typeparam name="TSource">Type of elements in <paramref name="source"/>.</typeparam> 
    /// <param name="source">Sequence of elements.</param> 
    /// <param name="element">Element which will become the first.</param> 
    /// <returns>A shifted sequence. For example Shift({1,2,3,4,5,6}, 3) would become {3,4,5,6,1,2}. </returns> 
    public static IEnumerable<TSource> Shift<TSource>(this IEnumerable<TSource> source, TSource element) 
    { 
     return Shift(source, element, EqualityComparer<TSource>.Default); 
    } 
1

Методы расширения, которые я использую наиболее бы быть те, в System.Linq.Enumerable классе.

И хорошее и полезное расширение этого списка вы можете найти в MoreLinq.

5

Большинство примеров методов расширения, которые я вижу здесь, противоречат лучшим практикам. Удлинительные методы являются мощными, но их следует использовать экономно. По моему опыту, для большинства из них обычно предпочтительнее статический класс помощника/утилиты со старым синтаксисом.

Есть что сказать для методов расширения для Enums, так как для них невозможно использовать методы. Если вы определяете их в том же пространстве имен, что и Enum и в той же сборке, они работают прозрачно.

7

я написал ряд методов расширения, чтобы сделать его легче манипулировать объектами ADO.NET и методы:

Создать DbCommand из DbConnection в одной инструкции:

public static DbCommand CreateCommand(this DbConnection connection, string commandText) 
    { 
     DbCommand command = connection.CreateCommand(); 
     command.CommandText = commandText; 
     return command; 
    } 

Добавить параметр к DbCommand:

public static DbParameter AddParameter(this DbCommand command, string name, DbType dbType) 
    { 
     DbParameter p = AddParameter(command, name, dbType, 0, ParameterDirection.Input); 
     return p; 
    } 

    public static DbParameter AddParameter(this DbCommand command, string name, DbType dbType, object value) 
    { 
     DbParameter p = AddParameter(command, name, dbType, 0, ParameterDirection.Input); 
     p.Value = value; 
     return p; 
    } 

    public static DbParameter AddParameter(this DbCommand command, string name, DbType dbType, int size) 
    { 
     return AddParameter(command, name, dbType, size, ParameterDirection.Input); 
    } 

    public static DbParameter AddParameter(this DbCommand command, string name, DbType dbType, int size, ParameterDirection direction) 
    { 
     DbParameter parameter = command.CreateParameter(); 
     parameter.ParameterName = name; 
     parameter.DbType = dbType; 
     parameter.Direction = direction; 
     parameter.Size = size; 
     command.Parameters.Add(parameter); 
     return parameter; 
    } 

DbDataReader доступа поля по имени, а не индекс:

public static DateTime GetDateTime(this DbDataReader reader, string name) 
    { 
     int i = reader.GetOrdinal(name); 
     return reader.GetDateTime(i); 
    } 

    public static decimal GetDecimal(this DbDataReader reader, string name) 
    { 
     int i = reader.GetOrdinal(name); 
     return reader.GetDecimal(i); 
    } 

    public static double GetDouble(this DbDataReader reader, string name) 
    { 
     int i = reader.GetOrdinal(name); 
     return reader.GetDouble(i); 
    } 

    public static string GetString(this DbDataReader reader, string name) 
    { 
     int i = reader.GetOrdinal(name); 
     return reader.GetString(i); 
    } 

    ... 

Другой (несвязанный) метод расширения позволяет мне выполнять операцию DragMove (например, WPF) на формах и элементах WinForms, see here.

0

Я автопилот следующего решить имя-класса-в-верхнее прецедентное URL проблемы в проектах MVC:

public static class RouteCollectionExt 
{ 
    public static Route MapRouteLowercase(this RouteCollection routes, string name, string url, object defaults) 
    { 
     var route = new LowercaseRoute(url, new RouteValueDictionary(defaults), new MvcRouteHandler()); 

     routes.Add(name, route); 

     return route; 
    } 

    private class LowercaseRoute : Route 
    { 
     public LowercaseRoute(string url, IRouteHandler routeHandler) 
      : base(url, routeHandler) { } 

     public LowercaseRoute(string url, RouteValueDictionary defaults, IRouteHandler routeHandler) 
      : base(url, defaults, routeHandler) { } 

     public LowercaseRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler) 
      : base(url, defaults, constraints, routeHandler) { } 

     public LowercaseRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler) 
      : base(url, defaults, constraints, dataTokens, routeHandler) { } 

     public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) 
     { 
      var path = base.GetVirtualPath(requestContext, values); 

      if (path != null) 
      { 
       path.VirtualPath = path.VirtualPath.ToLowerInvariant(); 
      } 

      return path; 
     } 
    } 
} 

Использование:

routes.MapRouteLowercase(
    "Default", 
    "{controller}/{action}/{id}", 
    new { controller = "Home", action = "Index", id = "" } 
); 
5

Хотя очень просто, я считаю, это один быть особенно полезно, так как я получаю страницу из полного результирующего набора десять миллиардов раз в проект:

public static class QueryableExtensions 
{ 
    public static IQueryable<T> Page(this IQueryable<T> query, int pageNumber, int pageSize) 
    { 
     int skipCount = (pageNumber-1) * pageSize; 
     query = query.Skip(skipCount); 
     query = query.Take(pageSize); 

     return query; 
    } 
} 
+0

Почему бы не написать его в одной строке? – nawfal

+0

@nawfal: Напишите что на одной строке? Это расширение удобства, и вам нужно вычислить skipCount .... так ....? – jrista

+0

Я думал, что это будет читать лучше: 'return query.Skip ((номер страницы - 1) * pageSize) .Take (pageSize)'. Просто вопрос вкуса. – nawfal

0
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Text.RegularExpressions; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      string guid1 = "936DA01F-9ABD-4d9d-80C7-02AF85C822A8"; 
      string guid2 = "936DA01F-9ABD-4d9d-80C7-02AF85C822A"; 
      Console.WriteLine("guid1: {0}", guid1.IsGuid()); 
      Console.WriteLine("guid2: {0}", guid2.IsGuid()); 
      Console.ReadLine(); 
     } 
    } 

    public static class GuidUtility 
    { 
     /// <summary> 
     /// Determines if string is legitimate GUID 
     /// </summary>  
     public static Boolean IsGuid(this String s) 
     { 
      string pattern = @"^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$"; 
      Regex regex = new Regex(pattern); 
      return regex.IsMatch(s); 
     } 
    } 
} 
+0

Очень приятно. Я бы точно подумал, что будет Guid.TryParse(). Я оказался ошибочным! – Pwninstein

+0

Вы должны изменить регулярное выражение, чтобы разрешить дополнительные фигурные скобки {936DA01F-9ABD-4d9d-80C7-02AF85C822A8}, так как это также действительный (и, вероятно, более распространенный) формат. –

+0

.net 4.0 имеет Guid.TryParse() - http://msdn.microsoft.com/en-us/library/system.guid.tryparse.aspx –

1

несколько расширений я использую в основном. Первый набор - это расширение объекта, действительно только для преобразования.

public static class ObjectExtension 
{ 
    public static T As<T>(this object value) 
    { 
     return (value != null && value is T) ? (T)value : default(T); 
    } 

    public static int AsInt(this string value) 
    { 
     if (value.HasValue()) 
     { 
      int result; 

      var success = int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out result); 

      if (success) 
      { 
       return result; 
      } 
     } 

     return 0; 
    } 

    public static Guid AsGuid(this string value) 
    { 
     return value.HasValue() ? new Guid(value) : Guid.Empty; 
    } 
} 

струнных расширения

public static class StringExtension 
{ 
    public static bool HasValue(this string value) 
    { 
     return string.IsNullOrEmpty(value) == false; 
    } 

    public static string Slug(this string value) 
    { 
     if (value.HasValue()) 
     { 
      var builder = new StringBuilder(); 
      var slug = value.Trim().ToLower(); 

      foreach (var c in slug) 
      { 
       switch (c) 
       { 
        case ' ': 
         builder.Append("-"); 
         break; 
        case '&': 
         builder.Append("and"); 
         break; 
        default: 

         if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') && c != '-') 
         { 
          builder.Append(c); 
         } 

         break; 
       } 
      } 

      return builder.ToString(); 
     } 

     return string.Empty; 
    } 

    public static string Truncate(this string value, int limit) 
    { 
     return (value.Length > limit) ? string.Concat(value.Substring(0, Math.Min(value.Length, limit)), "...") : value; 
    } 
} 

и последний являются некоторыми расширениями перечислений

public static class EnumExtensions 
{ 
    public static bool Has<T>(this Enum source, params T[] values) 
    { 
     var value = Convert.ToInt32(source, CultureInfo.InvariantCulture); 

     foreach (var i in values) 
     { 
      var mask = Convert.ToInt32(i, CultureInfo.InvariantCulture); 

      if ((value & mask) == 0) 
      { 
       return false; 
      } 
     } 

     return true; 
    } 

    public static bool Has<T>(this Enum source, T values) 
    { 
     var value = Convert.ToInt32(source, CultureInfo.InvariantCulture); 
     var mask = Convert.ToInt32(values, CultureInfo.InvariantCulture); 

     return (value & mask) != 0; 
    } 

    public static T Add<T>(this Enum source, T v) 
    { 
     var value = Convert.ToInt32(source, CultureInfo.InvariantCulture); 
     var mask = Convert.ToInt32(v, CultureInfo.InvariantCulture); 

     return Enum.ToObject(typeof(T), value | mask).As<T>(); 
    } 

    public static T Remove<T>(this Enum source, T v) 
    { 
     var value = Convert.ToInt32(source, CultureInfo.InvariantCulture); 
     var mask = Convert.ToInt32(v, CultureInfo.InvariantCulture); 

     return Enum.ToObject(typeof(T), value & ~mask).As<T>(); 
    } 

    public static T AsEnum<T>(this string value) 
    { 
     try 
     { 
      return Enum.Parse(typeof(T), value, true).As<T>(); 
     } 
     catch 
     { 
      return default(T); 
     } 
    } 
} 
+0

+1 Удивительный! Я не знаком с термином «slug» при работе со строками. Позаботьтесь о том, как использовать этот конкретный метод? Благодаря! – Pwninstein

+2

В основном это превратит «Автомобили и грузовики» в «легковые и грузовые автомобили» –

+0

Gotcha. Благодаря!! – Pwninstein

2

Чтобы более функционального код комбинатора:

public static Func<T, R> TryCoalesce<T, R>(this Func<T, R> f, R coalesce) 
    { 
     return x => 
      { 
       try 
       { 
        return f(x); 
       } 
       catch 
       { 
        return coalesce; 
       } 
      }; 
    } 
    public static TResult TryCoalesce<T, TResult>(this Func<T, TResult> f, T p, TResult coalesce) 
    { 
     return f.TryCoalesce(coalesce)(p); 
    } 

Тогда я мог бы написать что-то Лик е это:

public static int ParseInt(this string str, int coalesce) 
    { 
     return TryCoalesce(int.Parse, str, coalesce); 
    } 
+0

Проблема заключается в том, что это сделает ваш код ненадежным перед лицом фатальных исключений (AccessViolation, ExecutionEngineException, OutOufMemoryException, ...), потому что при безусловном «улове». –

+1

Большинство кода, как правило, ненадежны, когда заканчивается память ... – 2010-02-26 06:57:09

2

Другой набор я использую довольно часто для коалесценции IDictionary методы:

public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> d, TKey key, Func<TValue> valueThunk) 
    { 
     TValue v = d.Get(key); 
     if (v == null) 
     { 
      v = valueThunk(); 
      d.Add(key, v); 
     } 
     return v; 
    } 
    public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> d, TKey key, TValue coalesce) 
    { 
     return Get(d, key,() => coalesce); 
    } 

И для работы с коллекциями в целом:

public static IEnumerable<T> AsCollection<T>(this T item) 
    { 
     yield return item; 
    } 

Тогда для древовидных структур :

public static LinkedList<T> Up<T>(this T node, Func<T, T> parent) 
    { 
     var list = new LinkedList<T>(); 
     node.Up(parent, n => list.AddFirst(n)); 
     return list; 
    } 

Итак, я могу затем легко перемещаться и работать на платформе вверх в классе, как:

class Category 
{ 
    public string Name { get; set; } 
    public Category Parent { get; set; } 
} 

Далее, для облегчения композиции функций и более F # как способ программирования на C#:

public static Func<T, T> Func<T>(this Func<T, T> f) 
{ 
    return f; 
} 
public static Func<T1, R> Compose<T1, T2, R>(this Func<T1, T2> f, Func<T2, R> g) 
{ 
    return x => g(f(x)); 
} 
1

При регулярном использовании из StringBuilder, вы можете увидеть необходимость комбинирования AppendFormat() и AppendLine().

public static void AppendFormatLine(this StringBuilder sb, string format, params object[] args) 
{ 
    sb.AppendFormat(format, args); 
    sb.AppendLine(); 
} 

Кроме того, так как я преобразование приложения из VB6 в C#, следующие очень полезны для меня:

public static string Left(this string s, int length) 
{ 
    if (s.Length >= length) 
     return s.Substring(0, length); 
    throw new ArgumentException("Length must be less than the length of the string."); 
} 
public static string Right(this string s, int length) 
{ 
    if (s.Length >= length) 
     return s.Substring(s.Length - length, length); 
    throw new ArgumentException("Length must be less than the length of the string."); 
} 
5

Это метод расширения централизовать нулевые проверки перед поднятием событий.

public static class EventExtension 
{ 
    public static void RaiseEvent<T>(this EventHandler<T> handler, object obj, T args) where T : EventArgs 
    { 
     EventHandler<T> theHandler = handler; 

     if (theHandler != null) 
     { 
      theHandler(obj, args); 
     } 
    } 
} 
+0

+1. Но перед проверкой недействительности вы должны сначала скопировать экземпляр обработчика события в локальную переменную (экземпляр обработчика события является неизменным). Это предотвратило бы некоторое потенциальное состояние гонки в многопоточной среде (другой поток, возможно, отказался от подписки после проверки недействительности, но перед вызовом обработчика) –

+0

Это правда.Я делаю это в своем собственном коде, но так и не вернулся, чтобы изменить этот ответ. Я отредактировал свой ответ. –

+1

@Yann Trevin: это необязательно, потому что объект EventHandler уже скопирован один раз, когда передан в метод расширения в качестве параметра, поэтому нет условия гонки. – ShdNx

5

Часто я необходимо отобразить для пользователя значения на основе значения Enum, но не хотел идти пользовательский маршрут атрибутов, как это не кажется слишком элегантно.

С помощью этого удобного метода расширения:

public static string EnumValue(this MyEnum e) { 
    switch (e) { 
     case MyEnum.First: 
      return "First Friendly Value"; 
     case MyEnum.Second: 
      return "Second Friendly Value"; 
     case MyEnum.Third: 
      return "Third Friendly Value"; 
    } 
    return "Horrible Failure!!"; 
} 

Я могу это сделать:

Console.WriteLine(MyEnum.First.EnumValue()); 

Yay!

3

Это невероятно просто, но это проверка, которую я делаю, поэтому я закончил тем, что сделал для нее метод расширения. Мои любимые методы расширения, как правило, очень простые, простые, подобные этому, или как метод расширения Тейлора L для поднятия событий.

public static bool IsNullOrEmpty(this ICollection e) 
{ 
    return e == null || e.Count == 0; 
} 
+0

вы можете использовать 'IEnumerable' вместо' ICollection' – WiiMaxx

2

Я преобразовываю много Java в C#. Многие из методов различаются только в случае капитализации или других небольших различий синтаксиса.Так Java код, например

myString.toLowerCase(); 

не будет компилироваться, но добавив метод расширения

public static void toLowerCase(this string s) 
{ 
    s.ToLower(); 
} 

я могу поймать все методы (и я предполагаю, что хороший компилятор будет встраивать это так или иначе?).

Это, безусловно, сделало работу намного проще и надежнее. (Благодарю @Yuriy - см. Ответ в: differences between StringBuilder in Java and C#) за предложение.

0

когда-либо работал с Entity Framework & использовал строку кода, похожий на это снова и снова?

_context.EmployeeSet.Include("Department") 
    .Include("Manager").Include(...).Select(); 

Не проще сделать это:

_context.EmployeeSet.IncludeCommonReferenceses().Select(); 

`

internal static class ObjectContextExtensions 
{ 
    internal static ObjectQuery<Employee> IncludeCommonReferenceses(this ObjectQuery<Employee> employeeSet) 
    { 
     return employeeSet.Include(GetPropertyName<Employee>(e => e.Department)) 
      .Include(GetPropertyName<Employee>(e => e.Manager)).Include(...); 
    } 

    private static string GetPropertyName<T>(Expression<Func<T, object>> subSelector) 
    { 
     return ((MemberExpression)subSelector.Body).Member.Name; 
    } 
} 

Рекомендую вам сохранить имена свойств в consts, чтобы избежать использования отражения над & над agasin.

1

Мой любимый из моей личной коллекции струнных утилитами это тот, который будет анализировать сильно типизированных значение из строки для любого типа, который имеет метод TryParse:

public static class StringUtils 
{ 
    /// <summary> 
    /// This method will parse a value from a string. 
    /// If the string is null or not the right format to parse a valid value, 
    /// it will return the default value provided. 
    /// </summary> 
    public static T To<t>(this string value, T defaultValue) 
     where T: struct 
    { 
     var type = typeof(T); 
     if (value != null) 
     { 
      var parse = type.GetMethod("TryParse", new Type[] { typeof(string), type.MakeByRefType() }); 
      var parameters = new object[] { value, default(T) }; 
      if((bool)parse.Invoke(null, parameters)) 
       return (T)parameters[1]; 
     } 
     return defaultValue; 
    } 

    /// <summary> 
    /// This method will parse a value from a string. 
    /// If the string is null or not the right format to parse a valid value, 
    /// it will return the default value for the type. 
    /// </summary> 
    public static T To<t>(this string value) 
     where T : struct 
    { 
     return value.To<t>(default(T)); 
    } 
} 

Это отлично подходит для получения сильно типизированных информации из строки запроса:

var value = Request.QueryString["value"].To<int>(); 
1

Я ненавижу делать это везде:

DataSet ds = dataLayer.GetSomeData(1, 2, 3); 
if(ds != null){ 
    if(ds.Tables.Count > 0){ 
     DataTable dt = ds.Tables[0]; 
     foreach(DataRow dr in dt.Rows){ 
      //Do some processing 
     } 
    } 
} 

Вместо этого я обычно использую следующий метод расширения:

public static IEnumerable<DataRow> DataRows(this DataSet current){ 
    if(current != null){ 
     if(current.Tables.Count > 0){ 
      DataTable dt = current.Tables[0]; 
      foreach(DataRow dr in dt.Rows){ 
       yield return dr; 
      } 
     } 
    } 
} 

Таким образом, первый пример становится:

foreach(DataRow row in ds.DataRows()){ 
    //Do some processing 
} 

яй, методы расширения!

+0

Как часто ваши наборы данных имеют> 1 таблицу? Просто используйте foreach (DataRow dr в ds.Tables [0] .Rows) – tsilb

13

Я не являюсь поклонником интерфейса INotifyPropertyChanged, требующего, чтобы имена свойств передавались как строки. Я хочу строго типизированный способ проверить во время компиляции, что я только поднимаю и обрабатываю изменения свойств для существующих свойств. Я использую этот код, чтобы сделать это:

public static class INotifyPropertyChangedExtensions 
{ 
    public static string ToPropertyName<T>(this Expression<Func<T>> @this) 
    { 
     var @return = string.Empty; 
     if (@this != null) 
     { 
      var memberExpression = @this.Body as MemberExpression; 
      if (memberExpression != null) 
      { 
       @return = memberExpression.Member.Name; 
      } 
     } 
     return @return; 
    } 
} 

В классах, реализующих INotifyPropertyChanged я включаю этот вспомогательный метод:

protected void NotifySetProperty<T>(ref T field, T value, 
    Expression<Func<T>> propertyExpression) 
{ 
    if (field == null ? value != null : !field.Equals(value)) 
    { 
     field = value; 
     this.NotifyPropertyChanged(propertyExpression.ToPropertyName()); 
    } 
} 

Так что в конце концов я могу сделать такого рода вещи:

private string _name; 
public string Name 
{ 
    get { return _name; } 
    set { this.NotifySetProperty(ref _name, value,() => this.Name); } 
} 

Он сильно типизирован, и я только поднимаю события для свойств, которые фактически меняют их значение.

+0

Я использую переменные типа 'private static readonly PropertyChangedEventArgs _namePropertyChangedEventArgs = new PropertyChangedEventArgs (« Name »);' и передает их в 'OnPropertyChanged'. Намного легче отслеживать строки (найти все ссылки) и намного дешевле в памяти (создаётся только один раз для каждого типа, а не один раз для каждого экземпляра). –

+0

Hi 280Z28, возможно, сочетание методов было бы полезно, так как ваш подход все еще имеет строковый литерал, который нуждается в обновлении. На практике я считаю, что подход, который я использую, хорош, особенно потому, что изменения свойств обычно генерируются пользователями и поэтому являются медленными и нечастыми. Я должен проверить, чтобы убедиться, что я не создаю утечку памяти, хотя. Благодарю. – Enigmativity

0

Сравните любое данное свойство дано FILEINFO класса против другого ..

public static bool compare(this FileInfo F1,FileInfo F2,string propertyName) 
    { 
     try 
     { 
      System.Reflection.PropertyInfo p1 = F1.GetType().GetProperty(propertyName); 
      System.Reflection.PropertyInfo p2 = F2.GetType().GetProperty(propertyName); 

       if (p1.GetValue(F1, null) == p2.GetValue(F1, null)) 
       { 
        return true; 
       } 

     } 
     catch (Exception ex) 
     { 
      return false; 
     } 

     return false; 
    } 
0

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

public static void CopyStream(this Stream destination, Stream source) 
    { 
     if (source.CanSeek) 
     { 
      source.Position = 0; 
     } 
     int Length = 64000; 
     Byte[] buffer = new Byte[Length]; 
     int bytesRead = source.Read(buffer, 0, Length); 
     // write the required bytes 
     while (bytesRead > 0) 
     { 
      destination.Write(buffer, 0, bytesRead); 
      bytesRead = source.Read(buffer, 0, Length); 
     } 
    } 

Реализация:

MemoryStream result = new MemoryStream(); 
Stream s = new FileStream(tempDocFile, FileMode.Open); 

result.CopyStream(s); 

s.Close(); 
0

В многопоточных приложениях WPF (например, когда вы используете гнезда или таймеры) мне часто приходится ссылаться на GUI поток, чтобы изменить атрибуты WPF элемент. Это уродливый раздутый код, тем более, что вам нужно сделать это для каждого метода. Вот почему я сделал этот метод расширения:

/// <summary> 
    /// Invoke the element's thread using a dispatcher. This is needed for changing WPF element attributes. 
    /// </summary> 
    /// <param name="dispatcherObject">The element of which to use the thread.</param> 
    /// <param name="action">The action to do with the invoked thread.</param> 
    /// <param name="dispatcherPriority">The priority of this action.</param> 
    public static void DoInvoked(this System.Windows.Threading.DispatcherObject dispatcherObject, Action action, System.Windows.Threading.DispatcherPriority dispatcherPriority = System.Windows.Threading.DispatcherPriority.Render) 
    { 
     if (System.Threading.Thread.CurrentThread == dispatcherObject.Dispatcher.Thread) 
     { 
      action(); 
     } 
     else 
     { 
      dispatcherObject.Dispatcher.BeginInvoke(action, dispatcherPriority, null); 
     } 
    } 

Реализация:

public partial class MainWindow : Window 
{ 
    ... other code ... 
    void updateTime(object sender, ElapsedEventArgs e) 
    { 
     this.DoInvoked(() => textBoxStatus.Text = "Done."); 
    } 
} 
0

я бы, вероятно, использовать их наиболее для стесненных типов.

Что-то вроде:

public class Gallons 
{ 
    private int m_gallons; 

    public Gallons(int count) 
    { 
     if(count < 0) 
      throw new ArgumentException("Cannot have negative gallons"); 
     m_gallons = count; 
    } 

    static public Gallons operator + (Gallons left, Gallons right) 
    { 
     return new Gallons(left.m_gallons + right.m_gallons); 
    } 
    public override string ToString() 
    { 
     return m_gallons.ToString(); 
    } 
} 
public class Feet 
{ 
    private int m_feet; 

    public Feet(int count) 
    { 
     if(count < 0) 
      throw new ArgumentException("Cannot have negative feet"); 
     m_feet = count; 
    } 

    static public Feet operator +(Feet left, Feet right) 
    { 
     return new Feet(left.m_feet + right.m_feet); 
    } 
    public override string ToString() 
    { 
     return m_feet.ToString(); 
    } 
} 

public static class Conversions 
{ 
    static public Feet Feet(this int i) 
    { 
     return new Feet(i); 
    } 
    static public Gallons Gallons(this int i) 
    { 
     return new Gallons(i); 
    } 
} 

public class Test 
{ 
    static public int Main(string[] args) 
    { 
     System.Console.WriteLine(2.Feet() + 3.Feet()); // 5 
     System.Console.WriteLine(3.Gallons() + 4.Gallons()); // 7 
     System.Console.WriteLine(2.Feet() + 3.Gallons()); // doesn't compile - can't add feet to gallons! 
     return 0; 
    } 
} 
0

Некоторые из них уже опубликованы, но я просто хотел сказать, что я видел некоторые из этих нитей, и голоса не соответствуют действительности, что является полезным. ИМО, это список действительно наиболее полезных методов расширения

someCollection.ForEach(i => i.DoSomething()); 

Это очень и очень полезно, потому что он заменяет встроенный Еогеасп заявление, и мы все знаем, как часто это привыкает.

7.CreateSequence(); 

Это просто создает последовательность от 0 до 6. Могут быть другие версии, такие как указание начальной точки и шага. Это вторая наиболее полезная функция, потому что она заменяет цикл for. Некоторые люди говорят, что это дублирует функцию Enumerable.Range, что справедливо, но одна из вещей, которые мне нравятся с LINQ является слева направо упорядоченности, так что вы можете сделать что-то вроде этого

myCollection.Where(i => i.Something == somethingElse).Count().CreateSequence(). do something else 

Следующая наиболее Полезным является CastTo и As. Опять же они дублируют встроенные функции, но сохраняют порядок слева направо. Обратите внимание, что CastTo отличается от Cast, поскольку CastTo работает с одним объектом.

myObject.CastTo<Person>().DoSomething() 
myObject.As<Person>() 

Тогда есть SplitAsEnumerable. Это работает так же, как split, но не загружает все в память сразу. Это отлично подходит для синтаксического анализа больших файлов. Он работает с строкой или потоком.

myFileStream.SplitAsEnumerable("\r\n").Select(line => line.SplitAsEnumerable(",")) 

Последний способ - превратить коллекцию в строку. Это отлично подходит для отображения материала на экране или записи в файлы. например:

myTextBox.Text = "Top 3 scorers are " + myCollection.OrderBy(i => i.Score).Take(3).FlattenToString(i => i.Score.ToString(), ", "); 
+0

А где же реализации? – nawfal

0

Хотя я не писал эти два - я бы хотел.Найдено на http://lostechies.com/jimmybogard/2009/10/16/more-missing-linq-operators/

Append

public static IEnumerable<TSource> Append<TSource>(this IEnumerable<TSource> source, TSource element) 
{ 
    using (IEnumerator<TSource> e1 = source.GetEnumerator()) 
     while (e1.MoveNext()) 
      yield return e1.Current; 

    yield return element; 
} 

Prepend

public static IEnumerable<TSource> Prepend<TSource>(this IEnumerable<TSource> source, TSource element) 
{ 
    yield return element; 

    using (IEnumerator<TSource> e1 = source.GetEnumerator()) 
     while (e1.MoveNext()) 
      yield return e1.Current; 
} 
+0

Этот первый полезен для Max, когда коллекция может быть пуста или вы хотите указать минимум, например MyCollectionOfInts.Append (10) .Max(). Я также определяю метод Insert, чтобы вы могли добавлять элемент в любом месте. – MikeKulls

Смежные вопросы