Как получить несколько блокировок в VS2012, не испортив отступы

Это выглядит как глупый вопрос, но я не могу найти на него решение.

Моя проблема в том, что С# не позволяет получить несколько блокировок в одном выражении lock. Это не сработает:

lock (a, b, c, d)
{
    // ...
}

Вместо этого, кажется, требуется безумное количество отступов, чтобы сделать это:

lock (a)
    lock (b)
        lock (c)
            lock (d)
            {
                // ...
            }

В сочетании со всеми другими уровнями отступов, в которых уже находится код (пространства имен, класс, метод, условные операторы, циклы,...), это становится безумием. Поэтому вместо этого я хочу использовать это форматирование:

lock (a) lock (b) lock (c) lock (d)
{
    // ...
}

и сохранить мой рассудок. Но Visual Studio (я использую 2012) и слышать об этом не будет. Как только я ввожу любую закрывающую скобку, приведенное выше превращается во что-то глупое, например:

lock (a) lock (b) lock (c) lock (d)
                  {
                      // ...
                  }

И кажется, я ничего не могу сделать. Есть ли способ заставить это работать?


person Nikos C.    schedule 12.11.2014    source источник
comment
У вас установлен Resharper или аналогичный?   -  person Dave Zych    schedule 12.11.2014
comment
@DaveZych Нет, я не использую сторонние модули.   -  person Nikos C.    schedule 12.11.2014
comment
Можно было бы надеяться, что вы не делаете это часто. Получение нескольких блокировок, вероятно, является самым простым способом попасть в тупиковую ситуацию.   -  person Jim Mischel    schedule 12.11.2014
comment
Не ответ на ваш вопрос.. следовательно, комментарий.. зачем вам использовать так много блокировок для начала.. У вас либо действительно сложный и редкий сценарий.., либо это красный флаг.   -  person Vikas Gupta    schedule 12.11.2014
comment
можно отключить автоформатирование....   -  person Stan R.    schedule 12.11.2014
comment
В качестве альтернативы вы также можете перейти в Инструменты/Параметры/Текстовый редактор/С#/Вкладки и уменьшить размеры табуляции и отступа, скажем, до 2 пробелов, а не до 4. Вы все равно будете иметь отступ, но не так сильно. Я понимаю, что примерно на 8-м, 10-м или 12-м уровне отступа код становится трудно читать, но лично я думаю, что еще труднее читать, когда он не отступен.   -  person Ed Gibbs    schedule 13.11.2014
comment
@VikasGupta Это часть кода диагностики (для отладки). Этот код требует, чтобы все уязвимые критические секции не работали. Так что это не проблема для нормальной работы.   -  person Nikos C.    schedule 13.11.2014


Ответы (3)


Использование такого количества блокировок одновременно просто требует взаимоблокировки. Черт возьми, даже приобретение двух разных замков одновременно сопряжено с этим риском.

По крайней мере, вы должны быть очень очень осторожны и брать эти блокировки только в одном и том же порядке везде, где за один раз получается более одной блокировки.

Кроме того, «хорошее форматирование» в глазах смотрящего. То есть у каждого свое представление о том, что лучше. Но следующее должно работать без вмешательства VS, если вы специально не попросите об этом (например, запустив правило автоматического форматирования или явное автоматическое форматирование):

lock (a)
lock (b)
lock (c)
lock (d)
{
}

Вы также можете использовать этот подход с операторами using (где гораздо чаще используется более одного оператора подряд), когда VS IDE уже ожидает его.

person Peter Duniho    schedule 12.11.2014
comment
Почти работает, но не совсем: последний замок автоматически получает отступ. - person Nikos C.; 13.11.2014

Просто идея :-)

static class LockAndExecute
{
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    static void _gen(Action a, object[] objs, int i = 0){

        bool lockWasTaken = false;
        var temp = objs[i];
        try { 
            Monitor.Enter(temp, ref lockWasTaken); 
            if(i + 1 >= objs.Length) 
                a();
            else
                _gen(a, objs, i + 1);
        }
        finally 
        { 
            if (lockWasTaken) 
                Monitor.Exit(temp); 
        }
    }

    public static void Do(object[] objectsToLock, Action action){
            _gen(action, objectsToLock);
    }
}

и использование;

LockAndExecute.Do(new[]{a, b}, () => {
    Console.WriteLine("Eww!");
});
person Erti-Chris Eelmaa    schedule 12.11.2014

Вы можете обойти раздражающее поведение IDE, изменив свой код, хотя мысль об изменении кода для обхода поведения IDE немного мучает мою совесть. Я бы сделал это, если бы это был игрушечный проект, но не над чем-то серьезным, над чем мог бы работать другой разработчик.

Реализуйте блокировку с помощью реализации IDisposable. У оператора using нет раздражающей проблемы с отступами, которая есть у операторов lock.

class myLock : IDisposable
{
    private object _obj;

    public myLock(object obj)
    {
        _obj = obj;
        System.Threading.Monitor.Enter(obj);
    }

    public void Dispose()
    {
        System.Threading.Monitor.Exit(_obj);
        _obj = null;
    }

    public static void example()
    {
        var obj1 = new object();
        var obj2 = new object();
        var obj3 = new object();

        lock (obj1)
            lock (obj2)
                lock (obj3)
                {
                    // Stupid indentation >:(
                }

        using (new myLock(obj1))
        using (new myLock(obj2))
        using (new myLock(obj3))
        {
            // Ahhhh... :-)
        }
    }
}
person John Thoits    schedule 14.11.2020