Для тех, кто хочет знать, что события, связанные с последовательностью, вызываются, см. ниже. Пока что я тестировал только в Chrome.
WhereIf () Метод
var query = dc.Reviewer
.Where(r => r.FacilityID == facilityID)
.WhereIf(CheckBoxActive.Checked, r => r.IsActive);
public static IEnumerable<TSource> WhereIf<TSource>(
this IEnumerable<TSource> source,
bool condition, Func<TSource, bool> predicate)
{
if (condition)
return source.Where(predicate);
else
return source;
}
public static IQueryable<TSource> WhereIf<TSource>(
this IQueryable<TSource> source,
bool condition, Expression<Func<TSource, bool>> predicate)
{
if (condition)
return source.Where(predicate);
else
return source;
}
я также добавил перегрузки для индексного предиката в Где () дополнительный метод. Для большего количества забавы добавьте разновидность, которая 'еще' включает дополнительное предикат.
Встроенные Преобразования: Мне нравится этот небольшой шаблон. Завершенный это для булевской переменной и DateTime. Разработанный для следования за C# и как операторы.
public static Int32? AsInt32(this string s)
{
Int32 value;
if (Int32.TryParse(s, out value))
return value;
return null;
}
public static bool IsInt32(this string s)
{
return s.AsInt32().HasValue;
}
public static Int32 ToInt32(this string s)
{
return Int32.Parse(s);
{
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....
}
Меня раздражало, что LINQ дает мне OrderBy, который принимает в качестве аргумента класс, реализующий IComparer, но не поддерживает передачу простой анонимной функции сравнения. Я исправил это.
Этот класс создает IComparer из вашей функции сравнения ...
/// <summary>
/// Creates an <see cref="IComparer{T}"/> instance for the given
/// delegate function.
/// </summary>
internal class ComparerFactory<T> : IComparer<T>
{
public static IComparer<T> Create(Func<T, T, int> comparison)
{
return new ComparerFactory<T>(comparison);
}
private readonly Func<T, T, int> _comparison;
private ComparerFactory(Func<T, T, int> comparison)
{
_comparison = comparison;
}
#region IComparer<T> Members
public int Compare(T x, T y)
{
return _comparison(x, y);
}
#endregion
}
... и эти методы расширения предоставляют мои новые перегрузки OrderBy для перечисляемых объектов. Я сомневаюсь, что это работает для LINQ to SQL, но он отлично подходит для LINQ to Objects.
public static class EnumerableExtensions
{
/// <summary>
/// Sorts the elements of a sequence in ascending order by using a specified comparison delegate.
/// </summary>
public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
Func<TKey, TKey, int> comparison)
{
var comparer = ComparerFactory<TKey>.Create(comparison);
return source.OrderBy(keySelector, comparer);
}
/// <summary>
/// Sorts the elements of a sequence in descending order by using a specified comparison delegate.
/// </summary>
public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
Func<TKey, TKey, int> comparison)
{
var comparer = ComparerFactory<TKey>.Create(comparison);
return source.OrderByDescending(keySelector, comparer);
}
}
Вы можете поместить это в codeplex, если хотите.
Я нашел это полезным
public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> pSeq)
{
return pSeq ?? Enumerable.Empty<T>();
}
Он удаляет нулевую проверку в вызывающем коде. Теперь вы можете выполнить
MyList.EmptyIfNull().Where(....)
Ниже приведен метод расширения , который адаптирует код Рика Страла (и комментарии тоже), чтобы вам не приходилось угадывать или читать метку порядка байтов. массива байтов или текстового файла каждый раз, когда вы конвертируете его в строку.
Этот фрагмент позволяет вам просто сделать:
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();
}
}
}
}
Я нахожу этот довольно полезно:
public static class PaulaBean
{
private static String paula = "Brillant";
public static String GetPaula<T>(this T obj) {
return paula;
}
}
Вы можете использовать его на CodePlex.
Превратите это:
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
Для элементов управления Winform:
/// <summary>
/// Returns whether the function is being executed during design time in Visual Studio.
/// </summary>
public static bool IsDesignTime(this Control control)
{
if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
{
return true;
}
if (control.Site != null && control.Site.DesignMode)
{
return true;
}
var parent = control.Parent;
while (parent != null)
{
if (parent.Site != null && parent.Site.DesignMode)
{
return true;
}
parent = parent.Parent;
}
return false;
}
/// <summary>
/// Sets the DropDownWidth to ensure that no item's text is cut off.
/// </summary>
public static void SetDropDownWidth(this ComboBox comboBox)
{
var g = comboBox.CreateGraphics();
var font = comboBox.Font;
float maxWidth = 0;
foreach (var item in comboBox.Items)
{
maxWidth = Math.Max(maxWidth, g.MeasureString(item.ToString(), font).Width);
}
if (comboBox.Items.Count > comboBox.MaxDropDownItems)
{
maxWidth += SystemInformation.VerticalScrollBarWidth;
}
comboBox.DropDownWidth = Math.Max(comboBox.Width, Convert.ToInt32(maxWidth));
}
Использование IsDesignTime:
public class SomeForm : Form
{
public SomeForm()
{
InitializeComponent();
if (this.IsDesignTime())
{
return;
}
// Do something that makes the visual studio crash or hang if we're in design time,
// but any other time executes just fine
}
}
Использование SetDropdownWidth :
ComboBox cbo = new ComboBox { Width = 50 };
cbo.Items.Add("Short");
cbo.Items.Add("A little longer");
cbo.Items.Add("Holy cow, this is a really, really long item. How in the world will it fit?");
cbo.SetDropDownWidth();
Я забыл упомянуть, не стесняйтесь использовать их на Codeplex ...
Иногда удобно записать строку для выбранного элемента в списке с помощью настраиваемого разделителя.
Например, если у вас есть List
и хотите вывести фамилии, разделенные запятыми, вы можете сделать это.
string result = string.Empty;
foreach (var person in personList) {
result += person.LastName + ", ";
}
result = result.Substring(0, result.Length - 2);
return result;
Или вы можете использовать этот удобный метод расширения
public static string Join<T>(this IEnumerable<T> collection, Func<T, string> func, string separator)
{
return String.Join(separator, collection.Select(func).ToArray());
}
И использовать его так
personList.Join(x => x.LastName, ", ");
Что дает тот же результат, в данном случае список фамилий, разделенных через запятую.
Я использую их в своих проектах Silverlight:
public static void Show(this UIElement element)
{
element.Visibility = Visibility.Visible;
}
public static void Hide(this UIElement element)
{
element.Visibility = Visibility.Collapsed;
}
Двоичный поиск:
public static T BinarySearch<T, TKey>(this IList<T> list, Func<T, TKey> keySelector, TKey key)
where TKey : IComparable<TKey>
{
int min = 0;
int max = list.Count;
int index = 0;
while (min < max)
{
int mid = (max + min) / 2;
T midItem = list[mid];
TKey midKey = keySelector(midItem);
int comp = midKey.CompareTo(key);
if (comp < 0)
{
min = mid + 1;
}
else if (comp > 0)
{
max = mid - 1;
}
else
{
return midItem;
}
}
if (min == max &&
keySelector(list[min]).CompareTo(key) == 0)
{
return list[min];
}
throw new InvalidOperationException("Item not found");
}
Использование (при условии, что список отсортирован по Id):
var item = list.BinarySearch(i => i.Id, 42);
Тот факт, что он генерирует исключение InvalidOperationException, может показаться странным, но именно это делает Enumerable.First, когда нет подходящего элемента.
IEnumerable <>
Перемешать I использовал алгоритм Фишера-Йейтса для реализации функции перемешивания.
Используя yield return
и разбивая код на две функции, достигается правильная проверка аргумента и отложенное выполнение . (спасибо, Дэн , за указание на этот недостаток в моей первой версии)
static public IEnumerable<T> Shuffle<T>(this IEnumerable<T> source)
{
if (source == null) throw new ArgumentNullException("source");
return ShuffleIterator(source);
}
static private IEnumerable<T> ShuffleIterator<T>(this IEnumerable<T> source)
{
T[] array = source.ToArray();
Random rnd = new Random();
for (int n = array.Length; n > 1;)
{
int k = rnd.Next(n--); // 0 <= k < n
//Swap items
if (n != k)
{
T tmp = array[k];
array[k] = array[n];
array[n] = tmp;
}
}
foreach (var item in array) yield return item;
}
Вы все, наверное, уже знаете, что интересным использованием методов расширения является вид смеси . Некоторые методы-расширения, такие как XmlSerializable
, загрязняют практически каждый класс, и для большинства из них это не имеет смысла, как Thread
и SqlConnection
.
Часть функциональности должна быть явно смешана с классами, которые хотят ее иметь. Я предлагаю новую нотацию к этому типу, с префиксом M
.
XmlSerializable XmlSerializable
тогда, это:
public interface MXmlSerializable { }
public static class XmlSerializable {
public static string ToXml(this MXmlSerializable self) {
if (self == null) throw new ArgumentNullException();
var serializer = new XmlSerializer(self.GetType());
using (var writer = new StringWriter()) {
serializer.Serialize(writer, self);
return writer.GetStringBuilder().ToString();
}
}
public static T FromXml<T>(string xml) where T : MXmlSerializable {
var serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(new StringReader(xml));
}
}
Класс затем смешивает его в:
public class Customer : MXmlSerializable {
public string Name { get; set; }
public bool Preferred { get; set; }
}
И использование просто:
var customer = new Customer {
Name = "Guybrush Threepwood",
Preferred = true };
var xml = customer.ToXml();
Если вам нравится идея, вы можете создать новое пространство имён для полезных миксов в проекте. Что вы думаете?
О, и кстати, я думаю, что большинство методов расширения должны явно тестировать на нуль.
Класс Random
предоставляет множество функций.
Ниже приведены некоторые методы расширения, которые я время от времени использую. С ними, в дополнение к Next
и NextDouble
, класс Random
дает вам NextBool
, NextChar
, NextDateTime
, NextTimeSpan
, NextDouble
(принимает параметры minValue
и maxValue
) и мои личные ] избранное: NextString
. Есть и другие ( NextByte
, NextShort
, NextLong
и т. Д.); но они в основном предназначены для полноты и редко используются. Поэтому я не включил их сюда (этот код и так достаточно длинный!).
// todo: implement additional CharType values (e.g., AsciiAny)
public enum CharType {
AlphabeticLower,
AlphabeticUpper,
AlphabeticAny,
AlphanumericLower,
AlphanumericUpper,
AlphanumericAny,
Numeric
}
public static class RandomExtensions {
// 10 digits vs. 52 alphabetic characters (upper & lower);
// probability of being numeric: 10 / 62 = 0.1612903225806452
private const double AlphanumericProbabilityNumericAny = 10.0 / 62.0;
// 10 digits vs. 26 alphabetic characters (upper OR lower);
// probability of being numeric: 10 / 36 = 0.2777777777777778
private const double AlphanumericProbabilityNumericCased = 10.0 / 36.0;
public static bool NextBool(this Random random, double probability) {
return random.NextDouble() <= probability;
}
public static bool NextBool(this Random random) {
return random.NextDouble() <= 0.5;
}
public static char NextChar(this Random random, CharType mode) {
switch (mode) {
case CharType.AlphabeticAny:
return random.NextAlphabeticChar();
case CharType.AlphabeticLower:
return random.NextAlphabeticChar(false);
case CharType.AlphabeticUpper:
return random.NextAlphabeticChar(true);
case CharType.AlphanumericAny:
return random.NextAlphanumericChar();
case CharType.AlphanumericLower:
return random.NextAlphanumericChar(false);
case CharType.AlphanumericUpper:
return random.NextAlphanumericChar(true);
case CharType.Numeric:
return random.NextNumericChar();
default:
return random.NextAlphanumericChar();
}
}
public static char NextChar(this Random random) {
return random.NextChar(CharType.AlphanumericAny);
}
private static char NextAlphanumericChar(this Random random, bool uppercase) {
bool numeric = random.NextBool(AlphanumericProbabilityNumericCased);
if (numeric)
return random.NextNumericChar();
else
return random.NextAlphabeticChar(uppercase);
}
private static char NextAlphanumericChar(this Random random) {
bool numeric = random.NextBool(AlphanumericProbabilityNumericAny);
if (numeric)
return random.NextNumericChar();
else
return random.NextAlphabeticChar(random.NextBool());
}
private static char NextAlphabeticChar(this Random random, bool uppercase) {
if (uppercase)
return (char)random.Next(65, 91);
else
return (char)random.Next(97, 123);
}
private static char NextAlphabeticChar(this Random random) {
return random.NextAlphabeticChar(random.NextBool());
}
private static char NextNumericChar(this Random random) {
return (char)random.Next(48, 58);
}
public static DateTime NextDateTime(this Random random, DateTime minValue, DateTime maxValue) {
return DateTime.FromOADate(
random.NextDouble(minValue.ToOADate(), maxValue.ToOADate())
);
}
public static DateTime NextDateTime(this Random random) {
return random.NextDateTime(DateTime.MinValue, DateTime.MaxValue);
}
public static double NextDouble(this Random random, double minValue, double maxValue) {
if (maxValue < minValue)
throw new ArgumentException("Minimum value must be less than maximum value.");
double difference = maxValue - minValue;
if (!double.IsInfinity(difference))
return minValue + (random.NextDouble() * difference);
else {
// to avoid evaluating to Double.Infinity, we split the range into two halves:
double halfDifference = (maxValue * 0.5) - (minValue * 0.5);
// 50/50 chance of returning a value from the first or second half of the range
if (random.NextBool())
return minValue + (random.NextDouble() * halfDifference);
else
return (minValue + halfDifference) + (random.NextDouble() * halfDifference);
}
}
public static string NextString(this Random random, int numChars, CharType mode) {
char[] chars = new char[numChars];
for (int i = 0; i < numChars; ++i)
chars[i] = random.NextChar(mode);
return new string(chars);
}
public static string NextString(this Random random, int numChars) {
return random.NextString(numChars, CharType.AlphanumericAny);
}
public static TimeSpan NextTimeSpan(this Random random, TimeSpan minValue, TimeSpan maxValue) {
return TimeSpan.FromMilliseconds(
random.NextDouble(minValue.TotalMilliseconds, maxValue.TotalMilliseconds)
);
}
public static TimeSpan NextTimeSpan(this Random random) {
return random.NextTimeSpan(TimeSpan.MinValue, TimeSpan.MaxValue);
}
}
Я нахожу себя делающим это снова и снова, снова и снова...
public static bool EqualsIgnoreCase(this string a, string b)
{
return string.Equals(a, b, StringComparison.OrdinalIgnoreCase);
}
...затем StartsWithIgnoreCase
, EndsWithIgnoreCase
и ContainsIgnoreCase
.
Я только что просмотрел все 4 страницы этого документа и был довольно удивлен, что я этого не сделал » Я вижу этот способ сократить время проверки для InvokeRequired
:
using System;
using System.Windows.Forms;
/// <summary>
/// Extension methods acting on Control objects.
/// </summary>
internal static class ControlExtensionMethods
{
/// <summary>
/// Invokes the given action on the given control's UI thread, if invocation is needed.
/// </summary>
/// <param name="control">Control on whose UI thread to possibly invoke.</param>
/// <param name="action">Action to be invoked on the given control.</param>
public static void MaybeInvoke(this Control control, Action action)
{
if (control != null && control.InvokeRequired)
{
control.Invoke(action);
}
else
{
action();
}
}
/// <summary>
/// Maybe Invoke a Func that returns a value.
/// </summary>
/// <typeparam name="T">Return type of func.</typeparam>
/// <param name="control">Control on which to maybe invoke.</param>
/// <param name="func">Function returning a value, to invoke.</param>
/// <returns>The result of the call to func.</returns>
public static T MaybeInvoke<T>(this Control control, Func<T> func)
{
if (control != null && control.InvokeRequired)
{
return (T)(control.Invoke(func));
}
else
{
return func();
}
}
}
Использование:
myForm.MaybeInvoke(() => this.Text = "Hello world");
// Sometimes the control might be null, but that's okay.
var dialogResult = this.Parent.MaybeInvoke(() => MessageBox.Show(this, "Yes or no?", "Choice", MessageBoxButtons.YesNo));
Я часто использую это с нулевыми числами. Помогает отловить деление на 0, NaN, бесконечность...
public static bool IsNullOrDefault<T>(this T? o)
where T : struct
{
return o == null || o.Value.Equals(default(T));
}
При использовании словаря, где ключ является строкой, возвращайте существующий ключ, используя поиск без учета регистра. Мы использовали этот вариант для поиска путей к файлам.
/// <summary>
/// Gets the key using <paramref name="caseInsensitiveKey"/> from <paramref name="dictionary"/>.
/// </summary>
/// <typeparam name="T">The dictionary value.</typeparam>
/// <param name="dictionary">The dictionary.</param>
/// <param name="caseInsensitiveKey">The case insensitive key.</param>
/// <returns>
/// An existing key; or <see cref="string.Empty"/> if not found.
/// </returns>
public static string GetKeyIgnoringCase<T>(this IDictionary<string, T> dictionary, string caseInsensitiveKey)
{
if (string.IsNullOrEmpty(caseInsensitiveKey)) return string.Empty;
foreach (string key in dictionary.Keys)
{
if (key.Equals(caseInsensitiveKey, StringComparison.InvariantCultureIgnoreCase))
{
return key;
}
}
return string.Empty;
}
Аналогично строкам As и Is выше, но глобально для всех объектов.
Это довольно просто, но я часто использую их, чтобы облегчить взрыв паренса с помощью бокса.
public static class ExtensionMethods_Object
{
[DebuggerStepThrough()]
public static bool Is<T>(this object item) where T : class
{
return item is T;
}
[DebuggerStepThrough()]
public static bool IsNot<T>(this object item) where T : class
{
return !(item.Is<T>());
}
[DebuggerStepThrough()]
public static T As<T>(this object item) where T : class
{
return item as T;
}
}
Я буду рад, если этот код будет использоваться на codeplex, более того, он уже используется.
Мое предложение:
public static bool IsNullOrEmpty(this ICollection obj)
{
return (obj == null || obj.Count == 0);
}
Работает с коллекциями и массивами:
bool isNullOrEmpty = array.IsNullOrEmpty()
вместо
bool isNullOrEmpty = array == null || array.Length == 0;
GetMemberName позволяет получить строку с именем члена с безопасностью времени компиляции.
public static string GetMemberName<T, TResult>(
this T anyObject,
Expression<Func<T, TResult>> expression)
{
return ((MemberExpression)expression.Body).Member.Name;
}
Использование:
"blah".GetMemberName(x => x.Length); // returns "Length"
Он поставляется вместе со статическим методом без расширения, если вы этого не сделаете есть экземпляр:
public static string GetMemberName<T, TReturn>(
Expression<Func<T, TReturn>> expression)
where T : class
{
return ((MemberExpression)expression.Body).Member.Name;
}
Но вызов, конечно, выглядит не очень красиво:
ReflectionUtility.GetMemberName((string) s => s.Length); // returns "Length"
Вы можете поместить его в Codeplex, если хотите.
Два маленьких (некоторые люди считают их глупыми), которые я вставляю во все свои проекты:
public static bool IsNull(this object o){
return o == null;
}
и
public static bool IsNullOrEmpty(this string s){
return string.IsNullOrEmpty(s);
}
Это делает мой код намного более плавным ..
if (myClassInstance.IsNull()) //... do something
if (myString.IsNullOrEmpty()) //... do something
Я думаю, что это будет действительно хорошими свойствами расширения; если мы когда-нибудь их получим.
Уменьшает длину строки до toLength
и добавляет дополнительную строку в конец сокращенной строки, чтобы обозначить, что строка была сокращена (по умолчанию .. .
)
public static string Shorten(this string str, int toLength, string cutOffReplacement = " ...")
{
if (string.IsNullOrEmpty(str) || str.Length <= toLength)
return str;
else
return str.Remove(toLength) + cutOffReplacement;
}
FindControl со встроенным преобразованием типов:
public static T FindControl<T>(this Control control, string id) where T : Control
{
return (T)control.FindControl(id);
}
Ничего удивительного, но я чувствую, что это делает код более чистым.
// With extension method
container.FindControl<TextBox>("myTextBox").SelectedValue = "Hello world!";
// Without extension method
((TextBox)container.FindControl("myTextBox")).SelectedValue = "Hello world!";
При желании это можно поместить в проект codeplex
Этот может быть весьма полезным:
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> selector)
{
if (first == null)
throw new ArgumentNullException("first");
if (second == null)
throw new ArgumentNullException("second");
if (selector == null)
throw new ArgumentNullException("selector");
using (var enum1 = first.GetEnumerator())
using (var enum2 = second.GetEnumerator())
{
while (enum1.MoveNext() && enum2.MoveNext())
{
yield return selector(enum1.Current, enum2.Current);
}
}
}
Он был добавлен в класс Enumerable
в .NET 4.0, но его удобно иметь в 3.5.
Пример:
var names = new[] { "Joe", "Jane", "Jack", "John" };
var ages = new[] { 42, 22, 18, 33 };
var persons = names.Zip(ages, (n, a) => new { Name = n, Age = a });
foreach (var p in persons)
{
Console.WriteLine("{0} is {1} years old", p.Name, p.Age);
}
Я реализовал пакет методов расширения (доступен по адресу http://foop.codeplex.com/), и некоторые из моих повседневно используемых методов:
// the most beloved extension method for me is Pipe:
<%= variable.Pipe(x => this.SomeFunction(x)).Pipe(y =>
{
...;
return this.SomeOtherFunction(y);
}) %>
var d = 28.December(2009); // some extension methods for creating DateTime
DateTime justDatePart = d.JustDate();
TimeSpan justTimePart = d.JustTime();
var nextTime = d.Add(5.Hours());
using(StreamReader reader = new StreamReader("lines-of-data-file-for-example")) {
...
// for reading streams line by line and usable in LINQ
var query = from line in reader.Lines();
where line.Contains(_today)
select new { Parts = PartsOf(line), Time = _now };
}
500.Sleep();
XmlSerialize and XmlDeserialize
IsNull and IsNotNull
IfTrue, IfFalse and Iff:
true.IfTrue(() => Console.WriteLine("it is true then!");
IfNull and IfNotNull
Во время работы с MVC и имеющим множество , если
, если я забочусь ни о том, что я только забочусь о True
, либо false
, и печать NULL
, ИЛИ string.uppy
В другом случае я придумал:
public static TResult WhenTrue<TResult>(this Boolean value, Func<TResult> expression)
{
return value ? expression() : default(TResult);
}
public static TResult WhenTrue<TResult>(this Boolean value, TResult content)
{
return value ? content : default(TResult);
}
public static TResult WhenFalse<TResult>(this Boolean value, Func<TResult> expression)
{
return !value ? expression() : default(TResult);
}
public static TResult WhenFalse<TResult>(this Boolean value, TResult content)
{
return !value ? content : default(TResult);
}
Это позволяет мне изменить <% = (Wombool)? «Распечатать y»: String.uppyty%>
в <% = Coverool.whentrue («Печать Y»)%>
.
Я использую его только в моих представлениях, где я смешут код и HTML, в файлах кодов, написав версию «Дольше», является более четкой IMHO.
String.As
, который можно использовать для преобразования строкового значения as некоторого типа (предназначен для использования в основном с примитивами и типами, поддерживающими IConvertable. Отлично работает с Nullable
типами и даже Enums!
public static partial class StringExtensions
{
/// <summary>
/// Converts the string to the specified type, using the default value configured for the type.
/// </summary>
/// <typeparam name="T">Type the string will be converted to. The type must implement IConvertable.</typeparam>
/// <param name="original">The original string.</param>
/// <returns>The converted value.</returns>
public static T As<T>(this String original)
{
return As(original, CultureInfo.CurrentCulture,
default(T));
}
/// <summary>
/// Converts the string to the specified type, using the default value configured for the type.
/// </summary>
/// <typeparam name="T">Type the string will be converted to.</typeparam>
/// <param name="original">The original string.</param>
/// <param name="defaultValue">The default value to use in case the original string is null or empty, or can't be converted.</param>
/// <returns>The converted value.</returns>
public static T As<T>(this String original, T defaultValue)
{
return As(original, CultureInfo.CurrentCulture, defaultValue);
}
/// <summary>
/// Converts the string to the specified type, using the default value configured for the type.
/// </summary>
/// <typeparam name="T">Type the string will be converted to.</typeparam>
/// <param name="original">The original string.</param>
/// <param name="provider">Format provider used during the type conversion.</param>
/// <returns>The converted value.</returns>
public static T As<T>(this String original, IFormatProvider provider)
{
return As(original, provider, default(T));
}
/// <summary>
/// Converts the string to the specified type.
/// </summary>
/// <typeparam name="T">Type the string will be converted to.</typeparam>
/// <param name="original">The original string.</param>
/// <param name="provider">Format provider used during the type conversion.</param>
/// <param name="defaultValue">The default value to use in case the original string is null or empty, or can't be converted.</param>
/// <returns>The converted value.</returns>
/// <remarks>
/// If an error occurs while converting the specified value to the requested type, the exception is caught and the default is returned. It is strongly recommended you
/// do NOT use this method if it is important that conversion failures are not swallowed up.
///
/// This method is intended to be used to convert string values to primatives, not for parsing, converting, or deserializing complex types.
/// </remarks>
public static T As<T>(this String original, IFormatProvider provider,
T defaultValue)
{
T result;
Type type = typeof (T);
if (String.IsNullOrEmpty(original)) result = defaultValue;
else
{
// need to get the underlying type if T is Nullable<>.
if (type.IsNullableType())
{
type = Nullable.GetUnderlyingType(type);
}
try
{
// ChangeType doesn't work properly on Enums
result = type.IsEnum
? (T) Enum.Parse(type, original, true)
: (T) Convert.ChangeType(original, type, provider);
}
catch // HACK: what can we do to minimize or avoid raising exceptions as part of normal operation? custom string parsing (regex?) for well-known types? it would be best to know if you can convert to the desired type before you attempt to do so.
{
result = defaultValue;
}
}
return result;
}
}
Это опирается на другое простое расширение для Type
:
/// <summary>
/// Extension methods for <see cref="Type"/>.
/// </summary>
public static class TypeExtensions
{
/// <summary>
/// Returns whether or not the specified type is <see cref="Nullable{T}"/>.
/// </summary>
/// <param name="type">A <see cref="Type"/>.</param>
/// <returns>True if the specified type is <see cref="Nullable{T}"/>; otherwise, false.</returns>
/// <remarks>Use <see cref="Nullable.GetUnderlyingType"/> to access the underlying type.</remarks>
public static bool IsNullableType(this Type type)
{
if (type == null) throw new ArgumentNullException("type");
return type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof (Nullable<>));
}
}
Использование:
var someInt = "1".As<int>();
var someIntDefault = "bad value".As(1); // "bad value" won't convert, so the default value 1 is returned.
var someEnum = "Sunday".As<DayOfWeek>();
someEnum = "0".As<DayOfWeek>(); // returns Sunday
var someNullableEnum = "".As<DayOfWeek?>(null); // returns a null value since "" can't be converted
Я считаю весьма полезным следующий метод расширения:
public static T GetService<T>(this IServiceProvider provider)
{
return (T)provider.GetService(typeof(T));
}
Он значительно упрощает использование IServiceProvider
интерфейс. Сравните:
IProvideValueTarget target = (IProvideValueTarget)serviceProvider(typeof(IProvideValueTarget));
и
var target = serviceProvider.GetService<IProvideValueTarget>();