Настройка Microsoft Visual Studio для работы с IIS

Последний год я регулярно сталкиваюсь с зияющим пробелом в знаниях своих коллег в том месте, где должна находиться информация о способах хостинга веб-приложений asp.net и настройках этого самого хостинга. Устранять этот пробел всякий раз приходится индивидуально, всякий же раз вслух обещая себе написать заметку, на которую потом можно будет просто дать ссылку очередному страждущему. Кажется, время этой заметки пришло: сегодня я опишу интеграцию Visual Studio с IIS→

Кое-что о неявной типизации

Отгремели холивары. Герои починяют копья и готовятся к будущим битвам. Ну, а я выскажусь.
На мой взгляд, Илья выступил в пользу повсеместного использования неявной типизации в C# очень мощно и сурово, но абсолютно неубедительно.
Во всяком случае, с моей точки зрения.
Посудите сами→

Коллекция граблей

Наткнувшись сегодня в статье Александра Галкина «Немного об интерфейсах в .Net (по мотивам одного интервью)» на тот факт, что массив в .NET, оказывается, реализует многие члены интерфейса IList выбрасыванием NotSupportedException, я крайне удивился. Удивился, потому что привык, что .NET страхует программиста, не давая ему наступать на грабли, но в данном случае грабли лежат в основе основ фреймворка, в наисистемнейшем классе System.Array.  В чём же грабли, если эта недореализация недоступна в публичной области видимости? В возможности неявного приведения без каких-нибудь предупреждений.

Объявляет, к примеру, какой-нибудь программист интерфейс:

interface I
{
    void Test(IList collection);
}

Имеет, в общем-то, право.

Далее, какой-нибудь другой программист (ну, или тот же, неважно) реализует этот интерфейс:

class C : I
{
    public void Test(IList collection)
    {
        collection.Clear();
        // разные другие манипуляции
    }
}

И тоже имеет на это полное право.

Но потом приходит третий программист (ну, или тот же самый, но спустя пару месяцев), и пытается использовать этот интерфейс:

    C c = new C();
    c.Test(new[] { 1, 2, 3 });

И… получает NotSupportedException без объявления войны.
Особенно грустно становится, если вспомнить о том, что некоторые разработчики питают нездоровое пристрастие к неявной типизации (впрочем, про неё лучше отдельно как-нибудь), что чревато подобными участками кода:

    var integers = SomeFarObject.GetSomeCollectionOfIntegers(); // int[] GetSomeCollectionOfIntegers()…
    c.Test(integers);

Ой. А стукнет по лбу уже в рантайме — эксепшен вылетит прямо в лицо тестировщику (хорошо, если не клиенту). Неприятно.
Кто-нибудь в курсе, зачем System.Array реализует IList, с какой целью?

Использование атрибутов безопасности для контроля доступа к коду

Довелось мне недавно перерабатывать модель безопасности на немаленьком проекте с трудной судьбой. Модель получилась удобная, изящная, практичная, в ней по уму реализованы и красиво вписаны в бизнес-логику всякие участники, удостоверения и роли, и единственное, чего не хватало до полного счастья — атрибутов для лаконичного контроля использования кода вида «этот метод запускается только если у текущего пользователя есть такая-то роль». У меня внезапно нашлось несколько часов времени на исследования в этой области, и при ближайшем рассмотрении не менее внезапно оказалось, что для моей ситуации в .NET уже всё есть, осталось только научиться этим пользоваться. И тут внезапно оказалось (снова!), что готовый и полный howto на эту тему нагуглить неожиданно сложно — по крайней мере, мне не удалось этого сделать. Целостную картину пришлось собирать по кусочкам, и вот что получилось…

Такие разные одиночки

Данная запись является вольным переводом статьи Джона Скита «Implementing the Singleton Pattern in C#» (англ.), которая чрезвычайно понравилась мне как полнотой материала, так и манерой его подачи (с объяснением причин, особенностей и последствий).

Введение

Паттерн одиночка — один из наиболее известных паттернов проектирования. По сути, одиночка — класс, позволяющий создать лишь один свой экземпляр и обычно предоставляющий простой способ доступа к этому экземпляру. Чаще всего одиночки при создании экземпляра не позволяют указывать никаких параметров, так как в этом случае удовлетворение второго обращения с отличающимися параметрами было бы проблематично (в случае, если конкретный экземпляр должен быть доступен вызовам с одинаковыми параметрами, лучше использовать фабрику). Эта статья относится только к ситуации, когда параметры не нужны. Обычным требованием к одиночкам является ленивая инициализация, то есть создание экземпляра только тогда, когда в нём впервые возникает необходимость.
Реализовать одиночку в C# можно несколькими различными способами. Я опишу их здесь в порядке возрастания изящества, начиная с наиболее часто встречающегося потоконебезопасного способа и заканчивая самой ленивой, простой, потокобезопасной и производительной реализацией. Читать далее

Используя using

Один из моих самых любимых вопросов на собеседовании: в чём опасность такой конструкции?

…
using (MyClass myClass = new MyClass() { Prop = p })
{
    myClass.Use();
}

Выглядит вполне невинно — до тех пор, пока не начинаешь задумываться в том, как это устроено внутри→

…тем больше я люблю C#

Нашел недавно забавный трюк.
Иногда при реализации интерфейса удобно какой-либо из объявленных членов реализовать производным типом. Как-то так.

private interface I
{
    object P { get; }
}

private class C : I
{
    public string P
    {
        get
        {
            return "Hello world!";
        }
    }
}

Но напрямую, в лоб, сделать этого нельзя: сигнатуры членов класса и интерфейса получаются разными, и интерфейс очень обижается, не признавая такую реализацию, несмотря на то, что string прекрасно приводится к object.

Program.cs(12,17): error CS0738: 'Test1.Program.C' does not implement interface member 'Test1.Program.I.P'. 'Test1.Program.C.P' cannot implement 'Test1.Program.I.P' because it does not have the matching return type of 'object'.
Program.cs(9,11): (Related location)
Program.cs(14,18): (Related location)

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

private interface I
{
    object P { get; }
}

private class C : I
{
    public string P
    {
        get
        {
            return "Hello world!";
        }
    }

    object I.P
    {
        get
        {
            return this.P;
        }
    }
}

Правда, я совершенно не понимаю, откуда взялось ограничение, не позволяющее производному классу замещать базовый в этом контексте; более того, я без понятия, какими словами это гуглить. В msdn я ничего не нашел, лишь только аксиоматическое: жизнь несправедлива …член класса… …должен обладать таким же именем и сигнатурой, как член интерфейса, смирись с этим. Более того, я не совсем уверен, что у этого поведения есть цель, а не причина. В любом случае, если кто-нибудь знает причину, цель или кого-нибудь, кому уместно задать такой вопрос — черкните, пожалуйста, пару слов в комментариях.