Эта функция существует? Определение моих собственных фигурных скобок в C#

Вы будете ценить следующие два синтаксического сахара:

lock(obj)
{
//Code
}

same as:

Monitor.Enter(obj)
try
{
//Code
}
finally
{
Monitor.Exit(obj)
}

и

using(var adapt = new adapter()){
//Code2
}

same as:

var adapt= new adapter()
try{
//Code2
}
finally{
adapt.Dispose()
}

Очевидно первый пример в каждом случае более читаем. Существует ли способ определить такого рода вещь самостоятельно, или на языке C#, или в IDE? Причина, которую я спрашиваю, состоит в том, что существует много подобных использований (длинного вида), который извлек бы выгоду из этого, например, если Вы используете ReaderWriterLockSlim, Вы хотите что-то довольно подобное.

РЕДАКТИРОВАНИЕ 1:

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

myclass
{
ReaderWriterLockSlim rwl = new ReaderWriterLockSlim();

void MyConcurrentMethod()
{
  rwl.EnterReadLock();
  try{
    //Code to do in the lock, often just one line, but now its turned into 8!
  }
  finally
  {
    rwl.ExitReadLock();
  }
}
}

//I'd rather have:
void MyConcurrentMethod()
{
rwl.EnterReadLock()
{
   //Code block. Or even simpler, no brackets like one-line ifs and usings
}
}

Конечно, необходимо было бы дать некоторые мысли относительно того, как использовать TryEnterReadLocks и те виды вещей с возвратами. Но я уверен, что Вы могли думать о чем-то.

8
задан Carlos 21 May 2010 в 14:56
поделиться

10 ответов

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

void MyBrace(Action doSomething)
{      
     try
     {
        //wait for lock first

        doSomething();
     }
     finally
     {
         //special cleanup
     }
}

И используйте его так:

MyBrace(() => 
{
   //your code goes here, but won't run until the lock is obtained
});  // cleanup will always run, even if your code throws an exception

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

19
ответ дан 5 December 2019 в 05:18
поделиться

Думаю, вам нужны директивы препроцессора, но C # не поддерживает их . Наиболее близкими к нему могут быть фрагменты кода Visual Studio , которые вы можете спроектировать самостоятельно .

0
ответ дан 5 December 2019 в 05:18
поделиться

Как уже было сказано другими, IDisposable можно использовать для создания понятия области в вашем коде. Он даже может поддерживать вложение.

0
ответ дан 5 December 2019 в 05:18
поделиться

Нет, нет возможности определить свои собственные ключевые слова. Они определяются языком и встроены в компилятор для интерпретации в IL. Мы еще не достигли такого уровня абстракции!

Вы только посмотрите, как все приходят в восторг, когда появляются такие вещи, как var и dynamic .

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

1
ответ дан 5 December 2019 в 05:18
поделиться

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

Вы можете определить классы, реализующие IDisposable, чтобы инкапсулировать подобную семантику использования блоков. Например, если у вас есть класс, который инкапсулирует получение блокировки чтения ReaderWriterLockSlim (acquire on construct, release on Dispose), вы можете создать свойство вашего класса, которое конструирует экземпляр, что приводит к такому синтаксису:

using (this.ReadLock) // This constructs a new ReadLockHelper class, which acquires read lock
{
   //Do stuff here....
}
//After the using, the lock has been released.

Возможно, это злоупотребление IDisposable, но этот паттерн определенно используется в производственном коде.

Вы можете использовать аспектно-ориентированное программирование (с помощью таких инструментов, как PostSharp), чтобы обернуть тело метода многократно используемой логикой входа/выхода. Это часто используется для внедрения логирования или других сквозных проблем, которые вы хотели бы применить к своему коду, не загромождая его.

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

private void InReadLock(Action action)
{
   //Acquires the lock and executes action within the lock context
} 

Это может быть довольно мощным, поскольку поддержка лямбда-выражений с замыканиями позволяет реализовать произвольно сложную логику без ручного создания функций-оберток и передачи необходимых параметров в полях.

3
ответ дан 5 December 2019 в 05:18
поделиться

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

public class Program
{
  private static SharedLock m_Lock = new SharedLock();

  public static void SomeThreadMethod()
  {
    using (m_Lock.Acquire())
    {
    }
  }
}

public sealed class SharedLock
{
  private Object m_LockObject = new Object();

  public SharedLock()
  {
  }

  public IDisposable Acquire()
  {
    return new LockToken(this);
  }

  private sealed class LockToken : IDisposable
  {
    private readonly SharedLock m_Parent;

    public LockToken(SharedLock parent)
    {
      m_Parent = parent;
      Monitor.Enter(parent.m_LockObject);
    }

    public void Dispose()
    {
      Monitor.Exit(m_Parent.m_LockObject);
    }
  }
}
1
ответ дан 5 December 2019 в 05:18
поделиться

Я понимаю, что в следующей версии Visual Studio будет большой толчок к такой гибкости.

Вкл.net rocks, Андерс Хейлсберг недавно сказал, что одной из основных тем следующего выпуска Visual Studio (2012?) будет «компилятор как услуга», и с тех пор некоторые другие люди намекнули, что это откроется множество дверей для расширения языка и более тесной интеграции с DSL (предметно-ориентированными языками).

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

Это может немного поразить вас.

1
ответ дан 5 December 2019 в 05:18
поделиться

Лично я злоупотребляю 1 , используя для этого так, что у меня есть класс DisposeHelper для этого:

class DisposeHelper : IDisposable {
    private Action OnDispose { get; set; }

    public DisposeHelper(Action onDispose) {
        this.OnDispose = onDispose;
    }

    public void Dispose() {
        if (this.OnDispose != null) this.OnDispose();
    }
}

Это позволяет мне довольно легко вернуть IDisposable из произвольного метода:

IDisposable LogAction(string message) {
    Logger.Write("Beginning " + message);
    return new DisposeHelper(() => Logger.Write("Ending " + message));
}

using (LogAction("Long task")) {
   Logger.Write("In long task");
}

Вы также можете просто сделать это встроенным:

rw1.EnterReadLock();
using (new DisposeHelper(() => rw1.ExitReadLock()) {
   // do work
   return value;
}

Или, добавив onInit Action:

using (new DisposeHelper(() => rw1.EnterReadLock(), () => rw1.ExitReadLock())) {
   // do work
   return value;
}

, но это просто уродливо.

1 : Технически я полагаю, что это больше злоупотребление IDisposable , чем с использованием . В конце концов, я на самом деле действительно хочу try / finally - что дает мне с использованием . Однако оказалось, что мне нужно реализовать IDisposable , чтобы получить try / finally . В любом случае, меня это устраивает. Семантика для меня довольно ясна - если вы начнете что-то , я ожидаю, что вы закончите и что-то . Например, если вы напишете сообщение «Начало задачи» в файл журнала, я ожидаю также сообщения журнала «Завершение задачи». У меня просто более исчерпывающее определение «высвобождения ресурсов», чем у большинства разработчиков.

1
ответ дан 5 December 2019 в 05:18
поделиться

К сожалению, нет. Для поддержки этого компилятор C # должен быть более расширяемым для конечного пользователя. Это будет включать возможность определять свои собственные ключевые слова и иметь поддержку макросов и т. Д.

Однако вы можете создавать методы, которые хотя бы имеют немного похожее ощущение, например: (придуманный пример повторной реализации ключевого слова блокировки в коде пользователя)

public static class MyLocker
{
 public static void WithinLock(this object syncLock, Action action)
 {
  Monitor.Enter(syncLock)
  try
  {
   action();
  }
  finally
  {
   Monitor.Exit(syncLock)
  }
 }
}

использование then будет таким:

object lockObject = new object();
MyLocker.WithinLock(lockObject, DoWork);

public void DoWork()
{....}

ИЛИ

lockObject.WithinLock(DoWork);

ИЛИ

lockObject.WithinLock(()=>
{
 DoWork();
 //DoOtherStuff
});
5
ответ дан 5 December 2019 в 05:18
поделиться

Магический класс:

// Extend IDisposable for use with using
class AutoReaderWriterLockSlim : IDisposable {
    ReaderWriterLockSlim locker;
    bool disposed = false; // Do not unlock twice, prevent possible misuse
    // private constructor, this ain't the syntax we want.
    AutoReaderWriterLockSlim(ReaderWriterLockSlim locker) {
        this.locker = locker;
        locker.EnterReadLock();
    }
    void IDisposable.Dispose() { // Unlock when done
        if(disposed) return;
        disposed = true;
        locker.ExitReadLock();
    }
}
// The exposed API
public static class ReaderWriterLockSlimExtensions {
    public static IDisposable Auto(this ReaderWriterLockSlim locker) {
        return new AutoReaderWriterLockSlim(locker);
    }
}

Использование:

ReaderWriterLockSlim rwl = new ReaderWriterLockSlim();
using(rwl.Auto()) {
    // do stuff, locked
}
1
ответ дан 5 December 2019 в 05:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: