Десятилетиями поставщики инструментария и ученые мужи обещают, что создание средств, которые позволят отказаться от программирования, не за горами. Первым и, кажется, самым забавным случаем присвоения этого ярлыка, был язык Fortran. Fortran задумывался как средство, которое даст ученым и инженерам возможность просто набирать формулы и, таким образом, обойтись без помощи программистов.
…
За последние десятилетия программисты видели массу инструментов, которые предположительно должны были устранить необходимость программирования. Сначала это были языки третьего поколения, потом — четвертого. Потом — автоматическое программирование. Потом — CASE-средства. Потом — визуальное программирование. Каждое из этих достижений привносило значительные улучшения, и общими усилиями они сделали программирование абсолютно неузнаваемым для тех, кто изучал его до этих нововведений. Но ни одна из этих инноваций не устранила программирования как такового.
Причина в том, что программирование — принципиально сложный процесс даже при наличии хорошего инструментария. Дело не в инструментах — программистам приходится бороться с несовершенством реального мира; нам нужно досконально продумывать последовательности, зависимости и исключения, иметь дело с конечными пользователями, которые никак не могут ничего решить. Нам всегда придется бороться с плохо определенными интерфейсами с другими программными и аппаратными средствам и всегда принимать во внимание инструкции, бизнес-правила и другие источники сложных проблем, возникающие вне мира программирования.
Нам всегда будут нужны люди, способные заполнить брешь между задачей реального мира, которую нужно решить, и компьютером, предназначенным для решения этой задачи. Эти люди будут называться программистами независимо от того, манипулируют они машинными регистрами на ассемблере или диалоговыми окнами в Microsoft Visual Basic. Пока у нас есть компьютеры, нам будут нужны люди, которые говорят компьютерам, чтó делать, и эта деятельность будет называться программированием.
Когда вы слышите заявления о том, что «новый инструментарий устранит необходимость компьютерного программирования», бегите! Или хотя бы посмейтесь про себя над этим наивным оптимизмом.
…
За последние десятилетия программисты видели массу инструментов, которые предположительно должны были устранить необходимость программирования. Сначала это были языки третьего поколения, потом — четвертого. Потом — автоматическое программирование. Потом — CASE-средства. Потом — визуальное программирование. Каждое из этих достижений привносило значительные улучшения, и общими усилиями они сделали программирование абсолютно неузнаваемым для тех, кто изучал его до этих нововведений. Но ни одна из этих инноваций не устранила программирования как такового.
Причина в том, что программирование — принципиально сложный процесс даже при наличии хорошего инструментария. Дело не в инструментах — программистам приходится бороться с несовершенством реального мира; нам нужно досконально продумывать последовательности, зависимости и исключения, иметь дело с конечными пользователями, которые никак не могут ничего решить. Нам всегда придется бороться с плохо определенными интерфейсами с другими программными и аппаратными средствам и всегда принимать во внимание инструкции, бизнес-правила и другие источники сложных проблем, возникающие вне мира программирования.
Нам всегда будут нужны люди, способные заполнить брешь между задачей реального мира, которую нужно решить, и компьютером, предназначенным для решения этой задачи. Эти люди будут называться программистами независимо от того, манипулируют они машинными регистрами на ассемблере или диалоговыми окнами в Microsoft Visual Basic. Пока у нас есть компьютеры, нам будут нужны люди, которые говорят компьютерам, чтó делать, и эта деятельность будет называться программированием.
Когда вы слышите заявления о том, что «новый инструментарий устранит необходимость компьютерного программирования», бегите! Или хотя бы посмейтесь про себя над этим наивным оптимизмом.
👍13💯8👏1
StepOne | Степан Минин
Десятилетиями поставщики инструментария и ученые мужи обещают, что создание средств, которые позволят отказаться от программирования, не за горами. Первым и, кажется, самым забавным случаем присвоения этого ярлыка, был язык Fortran. Fortran задумывался как…
Стив Макконнелл, 1993 год.
Совершенный код, глава 30, раздел 30.6
Совершенный код, глава 30, раздел 30.6
👍7🤯3❤1🔥1
Завезли превью версию C# 12
Только недавно говорили о том, что пока у Microsoft мало чего есть, что можно было бы показать.
Впрочем, так и оказалось)
Новых фич всего три:
1️⃣ Первичные конструкторы для
2️⃣ Полноценный type alias
3️⃣ Значения по умолчанию для параметров в лямбдах
В целом ничего groundbreaking 🤷♂️
Только недавно говорили о том, что пока у Microsoft мало чего есть, что можно было бы показать.
Впрочем, так и оказалось)
Новых фич всего три:
1️⃣ Первичные конструкторы для
class и struct2️⃣ Полноценный type alias
3️⃣ Значения по умолчанию для параметров в лямбдах
В целом ничего groundbreaking 🤷♂️
Microsoft News
Check out new C# 12 preview features!
The first set of C# 12 features are here in preview including primary constructors, using aliases, and lambda expression parameters.
👍3🤔1👌1
Как изменить таймаут для конкретного запроса в
Одной из лучших практик по работе с
Однако, возникают ситуации, когда для разных запросов требуется разное поведение клиента. Например, разные таймауты.
Проблема в том, что
Но я бы не писал этот пост, если бы не существовало решения проблемы. А решение довольно простое:
Такое решение можно не только использовать "в лоб", но и обернуть в пайплайн из
1️⃣ Пользовательский таймаут меньше того, что установлен в
2️⃣ Пользовательский таймаут валиден. Проще говоря, время ожидания больше 0 секунд.
HttpClient?Одной из лучших практик по работе с
HttpClient в C# считается переиспользование одного экземпляра клиента для множества запросов. Как минимум во избежание port exhaustion.Однако, возникают ситуации, когда для разных запросов требуется разное поведение клиента. Например, разные таймауты.
Проблема в том, что
HttpClient.Timeout устанавливается единожды, во время создания клиента. И несмотря на наличие public set'тера, это значение не может быть изменено впоследствии. Любые попытки пресекаются выбрасыванием InvalidOperationException.Но я бы не писал этот пост, если бы не существовало решения проблемы. А решение довольно простое:
TimeSpan timeout = GetMyTimeout();
using (var tokenSource = new CancellationTokenSource(timeout))
{
var response = await httpClient.GetAsync(uri, tokenSource.Token);
HandleResponse(response);
}
Такое решение можно не только использовать "в лоб", но и обернуть в пайплайн из
DelegatingHandler'ов. Для того чтобы оно работало, потребуется убедиться в двух вещах:1️⃣ Пользовательский таймаут меньше того, что установлен в
HttpClient.Timeout2️⃣ Пользовательский таймаут валиден. Проще говоря, время ожидания больше 0 секунд.
👏8👍4🔥2🤩1
.NET не идеален
Производительность приложения в современном мире очень важный аспект, которым нельзя пренебрегать при разработке.
Это влияет и на пользовательский опыт, и на финансовые показатели продукта, его конкурентоспособность, репутацию.
Но даже проверенные временем платформы разработки не могут гарантировать ожидаемого поведения на 100% при соблюдении всех правил.
Например, Евгений Пешков в своём докладе рассказывает о неэффективности реализации базовых примитивов синхронизации асинхронных задач.
Оказывается, они содержат фатальный недостаток: используют внутри синхронные блокировки.
Также, автор доклада ведёт канал @epeshkblog, где можно прочитать про готовящееся им решение проблемы и множество других интересных аспектов платформы, о которых вы даже не догадывались.
Производительность приложения в современном мире очень важный аспект, которым нельзя пренебрегать при разработке.
Это влияет и на пользовательский опыт, и на финансовые показатели продукта, его конкурентоспособность, репутацию.
Но даже проверенные временем платформы разработки не могут гарантировать ожидаемого поведения на 100% при соблюдении всех правил.
Например, Евгений Пешков в своём докладе рассказывает о неэффективности реализации базовых примитивов синхронизации асинхронных задач.
Оказывается, они содержат фатальный недостаток: используют внутри синхронные блокировки.
Также, автор доклада ведёт канал @epeshkblog, где можно прочитать про готовящееся им решение проблемы и множество других интересных аспектов платформы, о которых вы даже не догадывались.
Telegram
.NET epeshk blog
Канал с заметками о C# и .NET
Поддержать канал: https://news.1rj.ru/str/blog_donate/2
Обратная связь: https://forms.gle/3uRz7FmzUA26Kw4y5
Поддержать канал: https://news.1rj.ru/str/blog_donate/2
Обратная связь: https://forms.gle/3uRz7FmzUA26Kw4y5
👍6🔥1👏1
Обобщай это, обобщай то
В новой статье вновь аккуратно стёр границы между абстрактной алгеброй и объектно-ориентированным программированием.
А ещё подробно зарылся внутрь
Жду вас на хабре с плюсом!
#хабр
В новой статье вновь аккуратно стёр границы между абстрактной алгеброй и объектно-ориентированным программированием.
А ещё подробно зарылся внутрь
System.Numerics и Generic Math.Жду вас на хабре с плюсом!
#хабр
🔥7👍3🤩1
Почему C#?
Думаю, читая этот канал или статьи на хабре, внимательный подписчик мог заметить, что я являюсь C# разработчиком.
Помимо общих материалов про IT делюсь решениями некоторых кейсов, и примеры кода всегда привожу именно на этом языке.
Конечно, это не единственный язык, который я знаю, причём хорошо. Но в своё время меня привлекла концепция C#.
В далёкие времена его позиционировали как работу над ошибками Java. И если вдаться в детали, то это соответствует действительности на все 100%. Сейчас, уже Java берёт многое от своего последователя.
В общем, если рассматривать шарпы не как ЯП, а как продукт, то у него крутое честное и продающее позиционирование.
Поделитесь в комментариях историей своего выбора ЯП
Думаю, читая этот канал или статьи на хабре, внимательный подписчик мог заметить, что я являюсь C# разработчиком.
Помимо общих материалов про IT делюсь решениями некоторых кейсов, и примеры кода всегда привожу именно на этом языке.
Конечно, это не единственный язык, который я знаю, причём хорошо. Но в своё время меня привлекла концепция C#.
В далёкие времена его позиционировали как работу над ошибками Java. И если вдаться в детали, то это соответствует действительности на все 100%. Сейчас, уже Java берёт многое от своего последователя.
В общем, если рассматривать шарпы не как ЯП, а как продукт, то у него крутое честное и продающее позиционирование.
Поделитесь в комментариях историей своего выбора ЯП
👍9👏2
Пока начинаются майские праздники, на хабре вышла публикация про IDE языка C#, выполняющая запросы LINQ для таблиц Excel.
Отличная статья, отличная разработка. Но, хочу обратить внимание, что это перевод, и автор разработки не из РФ. Могут быть нюансы с использованием и поддержкой.
Отличная статья, отличная разработка. Но, хочу обратить внимание, что это перевод, и автор разработки не из РФ. Могут быть нюансы с использованием и поддержкой.
Хабр
C# как замена VBA в Excel
Я довольно много пишу на C#, и это мне нравится. Время от времени мне хочется, чтобы можно было использовать C# внутри других приложений. Думаю, одним из таких приложений, в которых хорошо приживётся...
👍6🤯3🥰1
Многоликая регистрация в стандартном контейнере
Допустим, у нас есть некоторый класс, который реализует более одного интерфейса:
Наша задача зарегистировать экземпляр
Попытавшись совершить регистрацию наивным путём, мы потерпим неудачу, зависимости будут ссылаться на разные экземпляры
Но проблема вполне решаема, достаточно лишь зарегистрировать вначале экземпляр
Допустим, у нас есть некоторый класс, который реализует более одного интерфейса:
public interface IBar {}
public interface IFoo {}
public class FooBar : IFoo, IBar {}
Наша задача зарегистировать экземпляр
FooBar таким образом, чтобы при внедрении зависимостей IBar и IFoo использовался один и тот же объект.Попытавшись совершить регистрацию наивным путём, мы потерпим неудачу, зависимости будут ссылаться на разные экземпляры
FooBar:
services.AddSingleton<IFoo, FooBar>();
services.AddSingleton<IBar, FooBar>();
Но проблема вполне решаема, достаточно лишь зарегистрировать вначале экземпляр
FooBar и затем ссылаться на него:
services.AddSingleton<FooBar>();
services.AddSingleton<IFoo>(x => x.GetRequiredService<FooBar>());
services.AddSingleton<IBar>(x => x.GetRequiredService<FooBar>());
🔥19👍9🤯1
Всем доброе утро!
Я часто прохожу собеседования, на одном из последних встретил интересную задачу.
Решение выложу после 10 неудачных попыток в комментариях.
Надо определить, что будет выведено на экране. Допустим, у изначального потока
Я часто прохожу собеседования, на одном из последних встретил интересную задачу.
Решение выложу после 10 неудачных попыток в комментариях.
Надо определить, что будет выведено на экране. Допустим, у изначального потока
id равен 1, а при смене потока ему можно присвоить любой другой (2, 3, 10, 77 и так далее).
public static async Task<int> GetValue1()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId); // ?
return await Task.FromResult(100500);
}
public static async Task<int> GetValue2()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId); // ?
return 500100;
}
public static Task<int> GetValue3()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId); // ?
return Task.Run(() => 500100);
}
static async Task Main(string[] args)
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId); // 1
var val1 = await GetValue1();
Console.WriteLine(Thread.CurrentThread.ManagedThreadId); // ?
var val2 = await GetValue2();
Console.WriteLine(Thread.CurrentThread.ManagedThreadId); // ?
var val3 = await GetValue3();
Console.WriteLine(Thread.CurrentThread.ManagedThreadId); // ?
}
🤯6🤔4👍2❤1⚡1
StepOne | Степан Минин
Всем доброе утро! Я часто прохожу собеседования, на одном из последних встретил интересную задачу. Решение выложу после 10 неудачных попыток в комментариях. Надо определить, что будет выведено на экране. Допустим, у изначального потока id равен 1, а при…
Из-за разных обстоятельств чуть-чуть задержался с выкладыванием решения, но всё же в этом посте расставлю все точки над "i", как и обещал.
Но прежде, хочу выразить огромную радость по поводу того, какие подкованные у меня подписчики. В комментариях было много людей, ответивших правильно, причём сразу.
Затем, там началась интересная дискуссия, а далее вообще прислали уже новую задачу.
Для меня, как автора, работающего с аудиторией это большая победа, спасибо вам!
Итак, как уже было верно подмечено в комментах, программа выведет
Почему ответ именно такой?
Задача проверяет понимание того, в какой момент поток из ThreadPool действительно понадобится в случае
В методе
С
Ну а в случае
Но прежде, хочу выразить огромную радость по поводу того, какие подкованные у меня подписчики. В комментариях было много людей, ответивших правильно, причём сразу.
Затем, там началась интересная дискуссия, а далее вообще прислали уже новую задачу.
Для меня, как автора, работающего с аудиторией это большая победа, спасибо вам!
Итак, как уже было верно подмечено в комментах, программа выведет
"1 1 1 1 1 <любое другое число>". Здесь не подразумевались какие-то дополнительные условия, только конфигурация по умолчанию.Почему ответ именно такой?
Задача проверяет понимание того, в какой момент поток из ThreadPool действительно понадобится в случае
await'а.В методе
GetValue2 всё очевидно, поскольку ключевого слова await не было, соответственно автомат компилятором не сгенерируется, и код метода останется неизменным.С
GetValue1 всё чуть интереснее. Кажется, что произойдут все манипуляции, ведь есть и задачка, и await. Но runtime умнее, чем мы думаем и он понимает, что Task.FromResult, ровно как и Task.CompletedTask, создаёт уже завершенную задачу, которую не требуется ожидать. Соотвественно, смена потока не требуется.Ну а в случае
GetValue3, конечно смена потока произойдёт. Несмотря на элементарность задачи, Task.Run уже возвращает запущенную, но не завершённую.❤10👍1🔥1👏1🤩1
Внедрение конкретной реализации в стандартном контейнере
Допустим, у нас есть некоторый интерфейс, который имеет несколько реализаций:
И мы хотим, используя стандартный DI контейнер .NET Core, внедрить в определённый сервис конкретную реализацию этого контракта.
То есть:
К сожалению, стандартный контейнер не предоставляет встроенных возможностей для решения этой задачи.
Он спроектирован просто и минималистично, чтобы новый функционал было легко добавлять согласно индивидуальным потребностям.
Здесь есть несколько вариантов решения:
1⃣ Создание фабрики
2⃣ Создание Service Delegate
3⃣ Внедрение коллекции зависимостей
4⃣ Явная регистрация, например:
Конечно, указанные решения не идеальные.
В такой ситуации стоит посмотреть в сторону других контейнеров.
Ставьте реакции на этот пост, если хотите, чтобы я о них написал.
Допустим, у нас есть некоторый интерфейс, который имеет несколько реализаций:
public interface IDependency {}
public class DependencyImplOne : IDependency {}
public class DependencyImplTwo : IDependency {}
И мы хотим, используя стандартный DI контейнер .NET Core, внедрить в определённый сервис конкретную реализацию этого контракта.
То есть:
public class BarService : IBarService
{
public BarService(IDependency dependency) // DependencyImplOne
{
}
}
public class BazService : IBazService
{
public BazService(IDependency dependency) // DependencyImplTwo
{
}
}
К сожалению, стандартный контейнер не предоставляет встроенных возможностей для решения этой задачи.
Он спроектирован просто и минималистично, чтобы новый функционал было легко добавлять согласно индивидуальным потребностям.
Здесь есть несколько вариантов решения:
1⃣ Создание фабрики
2⃣ Создание Service Delegate
3⃣ Внедрение коллекции зависимостей
IEnumerable<IDependency> с её последующим перебором4⃣ Явная регистрация, например:
services.AddTransient<IBazService, BazService>(_ => new BazService(new DependencyImplTwo()))Конечно, указанные решения не идеальные.
В такой ситуации стоит посмотреть в сторону других контейнеров.
Ставьте реакции на этот пост, если хотите, чтобы я о них написал.
🔥32👍8🤩1
StepOne | Степан Минин
Внедрение конкретной реализации в стандартном контейнере Допустим, у нас есть некоторый интерфейс, который имеет несколько реализаций: public interface IDependency {} public class DependencyImplOne : IDependency {} public class DependencyImplTwo : IDependency…
Итак, любители внедрения зависимостей! Поскольку пост получил большой отклик, начинаю публиковать про другие контейнеры!
🔥6
StepOne | Степан Минин
Внедрение конкретной реализации в стандартном контейнере Допустим, у нас есть некоторый интерфейс, который имеет несколько реализаций: public interface IDependency {} public class DependencyImplOne : IDependency {} public class DependencyImplTwo : IDependency…
Simple Injector. Условная регистрация
Возможность внедрять конкретную реализацию зависимости согласно определённому контексту в этом контейнере реализована с помощью метода
Из приведённого примера видно, что условная регистрация позволяет настроить поставку зависимости на основе определения типа потребителя.
То есть,
Возможность внедрять конкретную реализацию зависимости согласно определённому контексту в этом контейнере реализована с помощью метода
RegisterConditional:
container.RegisterConditional<ILogger, NullLogger>(
c => c.Consumer.ImplementationType == typeof(HomeController));
container.RegisterConditional<ILogger, FileLogger>(
c => c.Consumer.ImplementationType == typeof(UsersController));
container.RegisterConditional<ILogger, DatabaseLogger>(c => !c.Handled);Из приведённого примера видно, что условная регистрация позволяет настроить поставку зависимости на основе определения типа потребителя.
То есть,
HomeController получит NullLogger, UsersController получит FileLogger, а все остальные потребители ILogger получат DatabaseLogger.⚡7👍2🔥2
StepOne | Степан Минин
Внедрение конкретной реализации в стандартном контейнере Допустим, у нас есть некоторый интерфейс, который имеет несколько реализаций: public interface IDependency {} public class DependencyImplOne : IDependency {} public class DependencyImplTwo : IDependency…
Castle Windsor. Явное указание зависимостей
Возвращаясь к нашему примеру с логгером, допустим, что у сервиса
В нём указывается конкретная зависимость, которую требуется внедрить.
Перегрузок метода много, соответственно вариантов это сделать несколько: от именованных зависимостей до явного указания типов.
Самый простой вариант будет выглядеть так:
Возвращаясь к нашему примеру с логгером, допустим, что у сервиса
ILogger есть две реализации: некий стандартный Logger и безопасный SecureLogger, который требуется использовать в некотором сервисе TransactionProcessingEngine.
В контейнере Castle Windsor это можно настроить, используя метод Dependency.OnComponent.В нём указывается конкретная зависимость, которую требуется внедрить.
Перегрузок метода много, соответственно вариантов это сделать несколько: от именованных зависимостей до явного указания типов.
Самый простой вариант будет выглядеть так:
container.Register(
Component.For<ITransactionProcessingEngine>().ImplementedBy<TransactionProcessingEngine>()
.DependsOn(Dependency.OnComponent<ILogger, SecureLogger>())
);👍10❤1👏1
Autofac. Именованные сервисы
Контейнер Autofac предоставляет возможность внедрять конкретные зависимости, явно указывая некоторый ключ, который соотносится с желаемой зависимостью.
Например, у нас есть сервис
Чтобы указать, что мы хотим внедрить конкретную реализацию
По указанному ключу, он проведёт фильтрацию и выберет нужную зависимость.
Пример:
Контейнер Autofac предоставляет возможность внедрять конкретные зависимости, явно указывая некоторый ключ, который соотносится с желаемой зависимостью.
Например, у нас есть сервис
IDisplay, отображающий какие-то произведения искусства IArtwork.Чтобы указать, что мы хотим внедрить конкретную реализацию
MyPainting, можно использовать атрибут KeyFilterAttribute.По указанному ключу, он проведёт фильтрацию и выберет нужную зависимость.
Пример:
public class ArtDisplay : IDisplay
{
public ArtDisplay([KeyFilter("MyPainting")] IArtwork art) { ... }
}
// ...
var builder = new ContainerBuilder();
builder.RegisterType<MyPainting>().Keyed<IArtwork>("MyPainting");
builder.RegisterType<ArtDisplay>().As<IDisplay>().WithAttributeFiltering();
// ...
var container = builder.Build();
⚡7👍1👏1
С Днём Победы!
Эта война и праздник останутся сакральными для русского человека, это глубоко в нас прописано на каком-то неизученном языке программирования человеческой сути.
Я точно также храню память и благодарен бабушкам и дедушкам, ковавшим победу.
Одним из этих людей является мой прадед, Воротников Николай Семёнович, кавалер Ордена Славы 3 степени, Ордена Красной Звезды и двух медалей За Отвагу.
Орден Славы он получил за то, что, выполняя приказ командования 24 декабря 1943 года, под вражеским обстрелом 13 раз устранял порванную связь с наблюдательными пунктами батарей дивизиона.
Дважды подвергаясь автоматному обстрелу, он сумел смотать 3 километра вражеского кабеля и, использовав его, установил связь с передовыми наблюдательными пунктами.
Чем обеспечил своевременное открытие огня дивизиону.
Смог бы так я?
Большой вопрос.
Хотя в мирной жизни прадед работал начальником АХО завода «Калибр».
Светлая память, с Праздником!
Эта война и праздник останутся сакральными для русского человека, это глубоко в нас прописано на каком-то неизученном языке программирования человеческой сути.
Я точно также храню память и благодарен бабушкам и дедушкам, ковавшим победу.
Одним из этих людей является мой прадед, Воротников Николай Семёнович, кавалер Ордена Славы 3 степени, Ордена Красной Звезды и двух медалей За Отвагу.
Орден Славы он получил за то, что, выполняя приказ командования 24 декабря 1943 года, под вражеским обстрелом 13 раз устранял порванную связь с наблюдательными пунктами батарей дивизиона.
Дважды подвергаясь автоматному обстрелу, он сумел смотать 3 километра вражеского кабеля и, использовав его, установил связь с передовыми наблюдательными пунктами.
Чем обеспечил своевременное открытие огня дивизиону.
Смог бы так я?
Большой вопрос.
Хотя в мирной жизни прадед работал начальником АХО завода «Калибр».
Светлая память, с Праздником!
❤26🤡11👍4👏2🕊1🥱1
StepOne | Степан Минин
Внедрение конкретной реализации в стандартном контейнере Допустим, у нас есть некоторый интерфейс, который имеет несколько реализаций: public interface IDependency {} public class DependencyImplOne : IDependency {} public class DependencyImplTwo : IDependency…
StructureMap. Настройка конструктора
Контейнер StructureMap позволяет решить задачу, используя настройку конструктора сервиса-потребителя.
Подход похож на то, что предлагает Autofac, но связывание происходит по имени параметра конструктора в потребителе контракта.
Например, у нас есть сервис для отправки сообщений
Какие-то ещё контейнеры уже не вижу смысла рассматривать, поскольку их подходы буду похожи на то, о чём я уже рассказал. Также, через какое-то время по совету подписчика сделаю бенчмарк, а пока переключусь на другую тему.
Контейнер StructureMap позволяет решить задачу, используя настройку конструктора сервиса-потребителя.
Подход похож на то, что предлагает Autofac, но связывание происходит по имени параметра конструктора в потребителе контракта.
Например, у нас есть сервис для отправки сообщений
IMessageService, который реализуют соответственно SmsService и EmailService. И есть некоторые сценарии, в которых нужно использовать разные имплементации, тогда конфигурация будет выглядеть примерно следующим образом:var container = new Container(x => {
x.For<FooScenario>().Use<FooScenario>()
.Ctor<IMessageService>("messageService")
.Is<SmsService>();
x.For<BarScenario>().Use<BarScenario>()
.Ctor<IMessageService>("messageService")
.Is<EmailService>();
});
// ...
public class FooScenario
{
public FooScenario(IMessageService messageService) // sms
}
// ...
public class BarScenario
{
public BarScenario(IMessageService messageService) // email
}
Какие-то ещё контейнеры уже не вижу смысла рассматривать, поскольку их подходы буду похожи на то, о чём я уже рассказал. Также, через какое-то время по совету подписчика сделаю бенчмарк, а пока переключусь на другую тему.
👍3❤2👏2🔥1🤩1👌1🕊1💯1
Анекдот, классический как книги дяди Боба:
Заходит однажды тестировщик в бар.
Забегает в бар.
Пролезает в бар.
Танцуя, проникает в бар.
Крадется в бар.
Врывается в бар.
Прыгает в бар.
Заказывает:
кружку пива,
2 кружки пива,
0 кружек пива,
999999999 кружек пива,
ящерицу в стакане,
–1 кружку пива,
qwerty кружек пива.
Первый реальный клиент заходит в бар и спрашивает, где туалет. Бар вспыхивает пламенем, все погибают.
Заходит однажды тестировщик в бар.
Забегает в бар.
Пролезает в бар.
Танцуя, проникает в бар.
Крадется в бар.
Врывается в бар.
Прыгает в бар.
Заказывает:
кружку пива,
2 кружки пива,
0 кружек пива,
999999999 кружек пива,
ящерицу в стакане,
–1 кружку пива,
qwerty кружек пива.
Первый реальный клиент заходит в бар и спрашивает, где туалет. Бар вспыхивает пламенем, все погибают.
😁30👍3🤩2🔥1
StepOne | Степан Минин
Многоликая регистрация в стандартном контейнере Допустим, у нас есть некоторый класс, который реализует более одного интерфейса: public interface IBar {} public interface IFoo {} public class FooBar : IFoo, IBar {} Наша задача зарегистировать экземпляр…
Пока не получается отойти от темы Dependency Injection на все 100%, как того хотелось бы.
Такое случается, когда погружаешься в тему глубоко и потребляешь много контента из разных источников.
Однако, пока я разбирался с контейнером StructureMap, обнаружил забавный факт.
Оказалось, что у него есть API для решения другой задачи, ранее обозначенной на канале:
Такое случается, когда погружаешься в тему глубоко и потребляешь много контента из разных источников.
Однако, пока я разбирался с контейнером StructureMap, обнаружил забавный факт.
Оказалось, что у него есть API для решения другой задачи, ранее обозначенной на канале:
var container = new Container(x =>
{
x.ForConcreteType<FooBar>().Configure.Singleton();
x.Forward<FooBar, IFoo>();
x.Forward<FooBar, IBar>();
});👍5🤔3👏1🤯1