Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
persons.OrderBy(p=>p.Age).First()
persons.OrderBy(p=>p.Age).Take(10)
persons.OrderBy(p=>p.Age).Skip(100).Take(10)
Приведение типа методом Of
ForEach
public static TResult Await<TResult>(this Task<TResult> operation) { var result = default(TResult); Task.Factory.StartNew(async () => result = await operation).Wait(); return result; }
operation.Result-то не угодил?Правда, непривычный синтаксис иногда получается, хотя в некотрых случаях выглядит красивее обычного.
Of и ForEachдостаточно operation.Result
return Task.Run(() => operation.Result).Result;
await operation.ConfigureAwait(false)?Task.Result? Он блокируется на текущем контексте синхронизации до завершения выполнения задачи. Как следствие, что произойдет при вызове кода: Task.Run(() => operation.Result).Result? Текущий код создаст задачу, которая будет ожидать выполнения переданной задачи, заблокирует текущий контекст и будет ждать выполнения. Если внутри переданной задачи тоже есть блокировка на контексте, то будет все тот же самый дедлок.await operation всегда и сразу приводит к возврату в поток SynchronizationContext, если он есть, а какой смысл делать эти переключения в тех классах, что отделены от пользовательского интерфейса? Я полагаю, что нагрузку на UI-поток нужно минимизировать (о чём особенно Android любит напоминать), так что как только ушли от взаимодействия с пользовательским интерфейсом, в диспетчеризации потоков лучше не использовать SynchronizationContext, а вернуться к нему непосредственно перед выдачей результатов пользователю.return Task.Run(() => operation.Result).Result;
var operation = OperationAsync();
return Task.Run(() => operation).Result; // Deadlock!!
return Task.Run(() => OperationAsync()).Result;
public static bool IsNullOrEmpty(this string value)
{
return string.IsNullOrEmpty(value);
}
monads.net
Особо умиляют полезностью методы TryDo/Catch, If/IfNot — просто гимн абсурду.
При дебаге такого когда вспомнишь весь словарь обсценной лексики в отношении автора.
int i = 10;
Console.WriteLine(i.Of<long>()); // bam
public static TResult Of<T, TResult>(this T o) where T : class
{
return (TResult) (object) o;
}
Error CS1061 'int' does not contain a definition for 'Of' and no extension method 'Of' accepting a first argument of type 'int' could be found
инжекции
ДекларацияВ русском языке конечно есть такие слова, но они не о том, о чём вы пишете.
Тут филолог для корнесловья
Отыщет новые условья,
Найдет, что русский корень есть
И слову чуждому «визиты»,
Успев стократно произнесть
Извозчику: «Да ну ж! вези ты!»
Язык наш — ключ заморских слов:
Восстань, возрадуйся, Шишков!
Не так твои потомки глупы;
В них руссицизм твоей души,
Твои родные «мокроступы»
И для визитов хороши.
Зачем же всё в чужой кумирне
Молиться нам? — Шишков! Ты прав,
Хотя — увы! — в твоей «ходырне»
Звук русский несколько дырав.
Тебя ль не чтить нам сердца вздохом,
В проезд визитный бросив взгляд
И зря, как, грозно бородат,
Маркер трактирный с «шаропёхом»
Стоит, склонясь на «шарокат»?
Декларировать, декларация чего-либо достаточно часто встречаются в документации для разработчиков.Смею предположить, речь идёт про документацию либо изначально русскую, либо с второсортным переводом на русский.
Например, начинающий разработчик встретился с понятием внедрение зависимостей и хочет найти английскую литературу по этому вопросу.Я ожидаю, что в хорошей литературе тут же будет дан оригинальный английский термин, как в википедии:
Я ожидаю, что в хорошей литературе тут же будет дан оригинальный английский термин, как в википедии
.method public hidebysig static !!T As<class T>(object o) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
// Размер кода: 12 (0xc)
.maxstack 8
IL_0000: ldarg.0
IL_0001: isinst !!T
IL_0006: unbox.any !!T
IL_000b: ret
} // end of method Sugar::As
switch (opcode)
// ...
case CEE_STARG:
case CEE_STARG_S: goto ARG_WRITE;
case CEE_LDARGA:
case CEE_LDARGA_S:
case CEE_LDLOCA:
case CEE_LDLOCA_S: goto ADDR_TAKEN;
ARG_WRITE:
if (compIsForInlining())
{
#ifdef DEBUG
if (verbose)
{
printf("\n\nInline expansion aborted due to opcode at offset [%02u] which writes to an argument\n",
codeAddr-codeBegp-1);
}
#endif
/* The inliner keeps the args as trees and clones them. Storing the arguments breaks that
* simplification. To allow this, flag the argument as written to and spill it before
* inlining. That way the STARG in the inlinee is trivial. */
inlineFailReason = "Inlinee writes to an argument.";
goto InlineNever;
}
else
public static T Of<T>(this object o)
{
return (T) o;
}
Кроме того, искусственно возможно даже смоделировать ситуацию вызова обработчика у объекта уже утилизированного сборщиком мусора. Конечно, это приведёт к исключению.
using System;
using System.Threading;
public class Program
{
public static SomeClass SomeClassInstance;
private static void Main()
{
new Thread(() =>
{
Thread.Sleep(100);
GC.Collect();
})
{ IsBackground = true }.Start();
var wr = new WeakReference(new SomeClass());
Console.WriteLine("IsAlive = {0}", wr.IsAlive);
((SomeClass)wr.Target).Foo();
Console.WriteLine("IsAlive = {0}", wr.IsAlive);
}
}
public class SomeClass
{
public SomeClass()
{
Console.WriteLine("Constructor called");
}
~SomeClass()
{
Console.WriteLine("Destructor called");
}
public void Foo()
{
Thread.Sleep(1000);
Console.WriteLine("Foo");
}
}
using System;
using System.Threading;
public class Program
{
public static event EventHandler SomeEvent = delegate { };
private static void Main()
{
object UnsubscribeObject = new object();
for(int i = 0; i < 2*1024*1024; i++)
{
var obj = new object();
SomeEvent += (sender, args) => obj.GetHashCode();
}
SomeEvent += (sender, args) => UnsubscribeObject.GetHashCode();
Console.WriteLine("Ready to start");
new Thread(() => SomeEvent(null, null)).Start();
Console.WriteLine("Event invocation started");
SomeEvent -= (sender, args) => UnsubscribeObject.GetHashCode();
UnsubscribeObject = null;
Console.WriteLine("UnsubscribeObject is null - {0}", UnsubscribeObject == null);
}
}
var handler = Handler — это присвоение ссылки (reference assignment), и оно в .net атомарно.Структуры копируются при присваивании. При присваивании структуры к новой переменной выполняется копирование всех данных, а любое изменение новой копии не влияет на данные в исходной копии. Это важно помнить при работе с коллекциями типов значений, такими как Dictionary<string, myStruct>.
EventHandler handler1 = (sender, eventArgs) => Console.WriteLine("1");
var handler2 = handler1;
handler2 += (sender, eventArgs) => Console.WriteLine("2");
handler1(null, EventArgs.Empty); // out => 1
Console.ReadKey();
handler2(null, EventArgs.Empty); // out => 1 , 2
Console.ReadKey();
У неизменных объектов нет проблем с многопоточностью.Поправка: нет проблем «внутри». Код снаружи все равно может столкнуться с проблемами — что иногда и происходит.
А вот подписка на событие с помощью лямды, это почти гарантированная утечка памяти!
viewModel[() => viewModel.Name].PropertyChanged += (o, e) => { // do somethig };
this[() => Name].PropertyChanged += (o, e) => { // do somethig };
А я и есть реалист, потер из своего кода, после того как в определенный момент профайлер показал мне наглядно, что я не прав!Наверно мне везёт, но пока ни разу не возникало хоть сколько-нибудь заметных тормозов из-за лямбд, какие бы они медленные ни были в синтетических тестах.
А какой смысл подписываться на свое событие? Это оверхед на ровном месте, разве нет?Не совсем понимаю, что вы имеете в виду.
this[() => Name].PropertyChanged += (o, e) => { // do somethig };
this.PropertyChanged += (o, e) =>
{
if (e.PropertyName != "Name") return;
// do something
};
public class WeakPropertyChangedListener
{
private WeakReference _weakEventListener;
private INotifyPropertyChanged _notifyCollectionChanged;
public WeakPropertyChangedListener(INotifyPropertyChanged notify, IWeakPropertyChangedListener eventListener)
{
if (notify == null
|| eventListener == null)
{
return;
}
_notifyCollectionChanged = notify;
_notifyCollectionChanged.PropertyChanged += PropertyChanged;
_weakEventListener = new WeakReference(eventListener);
}
private void PropertyChanged(object sender, PropertyChangedEventArgs e)
{
var listener = _weakEventListener;
if (listener == null)
{
return;
}
var eventListener = listener.Target as IWeakPropertyChangedListener;
if (eventListener != null)
{
eventListener.EventHandler(sender, e);
return;
}
Disconnect();
}
public void Disconnect()
{
var source = _notifyCollectionChanged;
_notifyCollectionChanged = null;
_weakEventListener = null;
if (source == null)
{
return;
}
source.PropertyChanged -= PropertyChanged;
}
}
nameof.PropertyChanged приспособили индексатор. Для общего совета это слишком смелое допущение — например, если модель составная и описывает список вложенных моделей, то новый индексатор будет семантически конфликтовать с существующим. Более поддерживаемое решение — сделать приватный метод Pty(Expression<Func<T>> expr) и заранее продумать архитектуру, чтобы для каждого свойства, изменение которого планируется отслеживать снаружи, было отдельное событие.protected bool SetValue<T>(ref T field, T value, Action<T, T> successHandler = null, [CallerMemberName] string propertyName = "")
{
Guard.NotNullAndEmpty(propertyName);
if (Equals(field, value))
{
return false;
}
var oldValue = field;
field = value;
OnPropertyChanged(propertyName);
if (successHandler != null)
{
successHandler(oldValue, field);
}
if (_trackChildProperties)
{
SubscribeToChildNotifications(field, propertyName);
}
return true;
}
private int _field;
public int Field
{
get { return _field; }
set { SetValue(ref _field, value); }
}
если модель составная и описывает список вложенных моделей, то новый индексатор будет семантически конфликтовать с существующим
и заранее продумать архитектуру, чтобы для каждого свойства, изменение которого планируется отслеживать снаружи, было отдельное событие.
Паттерн IDataErrorInfo работает через индексатор и это выглядит довольно красиво.
Не совсем понял, что вы имеете здесь в виду.
var a = usersListModel[1];
var b = usersListModel["Name"];
var c = usersListModel[() => CollectionChanged];
Сахарные инжекции в C#