Видел сообщение о скрытых функциях в C#, но не многие люди написали пример linq / lambdas, поэтому ... интересно ...
What's the coolest (as in the most elegant) use of the C# LINQ and/or Lambdas/anonymous delegates you have ever saw/written?
Бонус, если он тоже пошел в производство!





LINQ Raytracer, безусловно, возглавляет мой список =)
Я не совсем уверен, можно ли его назвать элегантным, но это определенно самое крутое linq-выражение, которое я когда-либо видел!
О, и просто чтобы быть предельно ясным; Я сделал это нет написал (Люк Хобан сделал)
Я слышал подкаст с Люком, где он говорил, что использовал трассировщик лучей, чтобы «проверить» новый язык. Поэтому, когда появился LINQ, он просто применил к нему свой стандартный «тест», и родился LINQ Raytracer.
Я пытался придумать крутой способ создания элемента управления навигацией для создаваемого мной веб-сайта. Я хотел использовать обычные неупорядоченные элементы списка HTML (с использованием стандартного CSS "Рыба-присоска" вид) с эффектом наведения мыши при верхней навигации, который открывает выпадающие элементы. У меня был зависящий от sql кешированный набор данных с двумя таблицами (NavigationTopLevels и NavigationBottomLevels). Затем все, что мне нужно было создать, это создать два объекта класса (TopNav и SubNav) с несколькими необходимыми свойствами (класс TopNav должен был иметь общий список элементов bottomnav -> List
var TopNavs = from n in ds.NavigationTopLevels select new TopNav { NavigateUrl = String.Format("{0}/{1}", tmpURL, n.id), Text = n.Text, id = n.id, SubItems = new List<SubNav>( from si in ds.NavigationBottomLevels where si.parentID == n.id select new SubNav { id = si.id, level = si.NavLevel, NavigateUrl = String.Format("{0}/{1}/{2}", tmpURL, n.id, si.id), parentID = si.parentID, Text = si.Text } ) }; List<TopNav> TopNavigation = TopNavs.ToList();
Возможно, это не самый «крутой» вариант, но для многих людей, которые хотят иметь динамическую навигацию, приятно не возиться с обычной логикой цикла, которая идет с этим. LINQ в этом случае помогает сэкономить время.
Некоторые основные функционалы:
public static class Functionals
{
// One-argument Y-Combinator.
public static Func<T, TResult> Y<T, TResult>(Func<Func<T, TResult>, Func<T, TResult>> F)
{
return t => F(Y(F))(t);
}
// Two-argument Y-Combinator.
public static Func<T1, T2, TResult> Y<T1, T2, TResult>(Func<Func<T1, T2, TResult>, Func<T1, T2, TResult>> F)
{
return (t1, t2) => F(Y(F))(t1, t2);
}
// Three-arugument Y-Combinator.
public static Func<T1, T2, T3, TResult> Y<T1, T2, T3, TResult>(Func<Func<T1, T2, T3, TResult>, Func<T1, T2, T3, TResult>> F)
{
return (t1, t2, t3) => F(Y(F))(t1, t2, t3);
}
// Four-arugument Y-Combinator.
public static Func<T1, T2, T3, T4, TResult> Y<T1, T2, T3, T4, TResult>(Func<Func<T1, T2, T3, T4, TResult>, Func<T1, T2, T3, T4, TResult>> F)
{
return (t1, t2, t3, t4) => F(Y(F))(t1, t2, t3, t4);
}
// Curry first argument
public static Func<T1, Func<T2, TResult>> Curry<T1, T2, TResult>(Func<T1, T2, TResult> F)
{
return t1 => t2 => F(t1, t2);
}
// Curry second argument.
public static Func<T2, Func<T1, TResult>> Curry2nd<T1, T2, TResult>(Func<T1, T2, TResult> F)
{
return t2 => t1 => F(t1, t2);
}
// Uncurry first argument.
public static Func<T1, T2, TResult> Uncurry<T1, T2, TResult>(Func<T1, Func<T2, TResult>> F)
{
return (t1, t2) => F(t1)(t2);
}
// Uncurry second argument.
public static Func<T1, T2, TResult> Uncurry2nd<T1, T2, TResult>(Func<T2, Func<T1, TResult>> F)
{
return (t1, t2) => F(t2)(t1);
}
}
Не принесите много пользы, если не знаете, как ими пользоваться. Чтобы знать это, вам нужно знать, для чего они:
Почему это все еще не стандартная функциональность .net?
Похоже на метод расширения linq Zip ().
Отчетность о прогрессе для длительных запросов LINQ. В сообщении блога вы можете найти метод расширения WithProgressReporting (), который позволяет обнаруживать и сообщать о ходе выполнения запроса linq.
Это не мой дизайн, но я использовал его несколько раз, оператор типизированного переключения: http://community.bartdesmet.net/blogs/bart/archive/2008/03/30/a-functional-c-type-switch.aspx
Спас меня так много, если ... еще если ... еще если ... еще ЕСЛИ! заявления
ух ты! всегда впечатлен тем, что люди придумали с 555, возможно, мы слишком часто живем в типизированном мире.
Этот подход сейчас практически устарел, начиная с C# 7.
Я думаю, что LINQ - это серьезное изменение в .NET, и это очень мощный инструмент.
Я использую LINQ to XML в производстве для анализа и фильтрации записей из XML-файла размером 6 МБ (с 20+ уровнями узлов) в набор данных в двух строках кода.
До LINQ для отладки требовались сотни строк кода и дни.
Это то, что я называю элегантным!
Это точно :-) Я люблю это.
Заставляет меня задаться вопросом, почему нам пришлось так долго ждать появления такой технологии?
На самом деле, я очень горжусь этим для создания документов Excel: http://www.aaron-powell.com/linq-to-xml-to-excel
Ссылка больше не активна?
@asgerhallas - Я обновил ссылку на моем обновленном сайте.
Работа с атрибутами:
private void WriteMemberDescriptions(Type type)
{
var descriptions =
from member in type.GetMembers()
let attributes = member.GetAttributes<DescriptionAttribute>(true)
let attribute = attributes.FirstOrDefault()
where attribute != null
select new
{
Member = member.Name,
Text = attribute.Description
};
foreach(var description in descriptions)
{
Console.WriteLine("{0}: {1}", description.Member, description.Text);
}
}
Метод расширения GetAttributes:
public static class AttributeSelection
{
public static IEnumerable<T> GetAttributes<T>(this ICustomAttributeProvider provider, bool inherit) where T : Attribute
{
if (provider == null)
{
throw new ArgumentNullException("provider");
}
return provider.GetCustomAttributes(typeof(T), inherit).Cast<T>();
}
}
AttributeSelection - это производственный код, который также определяет GetAttribute и HasAttribute. В этом примере я решил использовать предложения let и where.
Совсем недавно я сделал одну (немного сумасшедшую, но интересную) вещь вроде этой:
Безусловно, самая впечатляющая реализация Linq, с которой я когда-либо сталкивался, - это фреймворк Brahma.
Его можно использовать для разгрузки параллельных вычислений на GPU с помощью Linq to GPU. Вы пишете «запрос» в linq, а затем Брахма переводит его в HLSL (язык шейдеров высокого уровня), чтобы DirectX мог обработать его на графическом процессоре.
Этот сайт позволит мне вставить только одну ссылку, поэтому попробуйте эту веб-трансляцию от dotnetrocks:
http://www.dotnetrocks.com/default.aspx?showNum=466
В противном случае Google для проекта Brahma, вы получите нужные страницы.
Чрезвычайно классная штука.
ГДж
На мой взгляд, двойственность между делегатами (Func<T,R>, Action<T>) и выражениями (Expression<Func<T,R>>Expression<Action<T>>) является причиной наиболее умного использования лямбда-выражений.
Например:
public static class PropertyChangedExtensions
{
public static void Raise(this PropertyChangedEventHandler handler, Expression<Func<object>> propertyExpression)
{
if (handler != null)
{
// Retrieve lambda body
var body = propertyExpression.Body as MemberExpression;
if (body == null)
throw new ArgumentException("'propertyExpression' should be a member expression");
// Extract the right part (after "=>")
var vmExpression = body.Expression as ConstantExpression;
if (vmExpression == null)
throw new ArgumentException("'propertyExpression' body should be a constant expression");
// Create a reference to the calling object to pass it as the sender
LambdaExpression vmlambda = Expression.Lambda(vmExpression);
Delegate vmFunc = vmlambda.Compile();
object vm = vmFunc.DynamicInvoke();
// Extract the name of the property to raise a change on
string propertyName = body.Member.Name;
var e = new PropertyChangedEventArgs(propertyName);
handler(vm, e);
}
}
}
Тогда вы можете «безопасно» внедрить INotifyPropertyChanged, позвонив
if (PropertyChanged != null)
PropertyChanged.Raise( () => MyProperty );
Примечание: сначала я увидел это в Интернете несколько недель назад, затем потерял ссылку, и с тех пор тут и там появилось множество вариантов, поэтому, боюсь, я не могу дать надлежащую атрибуцию.
Возможно, не самые крутые, но в последнее время я использую их каждый раз, когда у меня есть блок кода, который снова и снова загружает C + Pd только для того, чтобы изменить несколько строк. Например, выполнение простых команд SQL для получения данных может быть выполнено следующим образом:
SqlDevice device = GetDevice();
return device.GetMultiple<Post>(
"GetPosts",
(s) => {
s.Parameters.AddWithValue("@CreatedOn", DateTime.Today);
return true;
},
(r, p) => {
p.Title = r.Get<string>("Title");
// Fill out post object
return true;
}
);
Что может вернуть список сообщений, которые были созданы сегодня. Таким образом, мне не нужно пятнадцать миллионов раз копировать и вставлять блок try-catch-finally для каждой команды, объекта и т. д.
Реактивные запросы LINQ OLINQ через INotifyingCollection - они позволяют выполнять (помимо прочего) агрегирование в реальном времени для больших наборов данных.
Напоминает мне Madlebrot в SQL: thedailywtf.com/Articles/…