这个功能存在吗?在 C# 中定义我自己的大括号

发布于 2024-09-02 14:21:45 字数 979 浏览 7 评论 0原文

您将欣赏以下两个语法糖:

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 和那些类型有回报的东西。但我相信你能想到一些事情。

You'll appreciate the following two syntactic sugars:

lock(obj)
{
//Code
}

same as:

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

and

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

same as:

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

Clearly the first example in each case is more readable. Is there a way to define this kind of thing myself, either in the C# language, or in the IDE? The reason I ask is that there are many similar usages (of the long kind) that would benefit from this, eg. if you're using ReaderWriterLockSlim, you want something pretty similar.

EDIT 1:

I've been asked to provide an example, so I'll give it a go:

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
}
}

Of course you'd have to give some thoughts as to how to use the TryEnterReadLocks and those kinds of things with returns. But I'm sure you could think of something.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

剪不断理还乱 2024-09-09 14:21:45

不完全是这样,但您可以使用操作委托来获得接近的结果:

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

请注意,这有一些限制。例如,新大括号内不能有有意义的 return 语句。感谢闭包,您至少仍然可以使用局部变量。

Not exactly, but you can use an action delegate to get something close:

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

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

And use it like this:

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

Note that there are some limitations with this. You can't have a meaningful return statement inside the new braces, for example. Thanks to closures you will at least still be able to use local variables.

昵称有卵用 2024-09-09 14:21:45

不幸的是没有。为了支持这一点,c# 编译器需要为最终用户提供更多的可扩展性。这包括能够定义自己的关键字并具有宏支持等...

但是您可以做的是构建至少具有一些类似感觉的方法,例如:
(在用户代码中重新实现 lock 关键字的设计示例)

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()
{....}

OR

lockObject.WithinLock(DoWork);

OR

lockObject.WithinLock(()=>
{
 DoWork();
 //DoOtherStuff
});

Unfortuanetly not. In order to support this the c# compiler would need to be more extensible for the end user. This would include being able to define your own keywords and have macro support etc...

However what you can do is build methods that at least have a bit of a similar feel such as this:
(contrieved example of reimplementing lock keyword in user code)

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

using then would be like this:

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

public void DoWork()
{....}

OR

lockObject.WithinLock(DoWork);

OR

lockObject.WithinLock(()=>
{
 DoWork();
 //DoOtherStuff
});
场罚期间 2024-09-09 14:21:45

您无法直接定义这样的构造,但有一些方法可以创建类似的简洁模式:

您可以定义实现 IDisposable 的类来封装这种块使用语义。例如,如果您有某个类封装了获取 ReaderWriterLockSlim(在构造时获取,在 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
} 

这可能非常强大,因为对带有闭包的 lambda 表达式的支持允许任意复杂的逻辑,而无需手动创建包装函数并在字段中传递所需参数。

You can't define constructs like this directly, but there are ways to create similar concise patterns:

You can define classes that implement IDisposable to encapsulate this sort of block usage semantics. For instance, if you had some class that encapsulated acquiring a ReaderWriterLockSlim (acquire on construct, release on Dispose) read lock, you could create a property on your class that constructs the instance, which results in a syntax like this:

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

This is arguably an abuse of IDisposable, but this pattern has definitely been used in production code.

You can use Aspect-oriented programming (with tools like PostSharp) to wrap a method body with reusable entry/exit logic. This is often used to inject logging or other cross-cutting concerns that you'd like to apply to your code without cluttering it up.

You can write functions that take delegates as parameters, which then wrap up the delegated logic in some similar structure. For instance, for the ReaderWriterLockSlim again, you can create a method like this:

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

This can be quite powerful, as the support for lambda expression with closures allows for arbitrarily complex logic without manually creating wrapper functions and passing required parameters in fields.

毁梦 2024-09-09 14:21:45

不,没有办法定义您自己的关键字。它们由语言定义并内置于编译器中以解释为 IL。我们还没有完全达到那个抽象级别!

只要看看当 vardynamic 之类的东西被引入时,每个人都会多么兴奋。

考虑到这一点,编辑您的帖子以显示您希望 ReaderWriterLockSlim 示例的语法。看看会很有趣。

No, there is no way to define your own keywords. These are defined by the language and are built into the compiler to interpret to IL. We haven't quite reached that level of abstraction yet!

Just look at how excited everyone gets when things like var and dynamic are introduced.

With that in mind, edit your post to show what you'd like the syntax to be for the ReaderWriterLockSlim example. It'd be interesting to see.

浅忆 2024-09-09 14:21:45

没有任何本机功能可以满足您的要求。但是,您只需实现 IDisposable 即可利用 using 语句。

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);
    }
  }
}

There is no native feature that does what you want. However, you can exploit the using statement simply by implementing 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);
    }
  }
}
汐鸠 2024-09-09 14:21:45

就我个人而言,我为此过度滥用1 using,以至于我有一个 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< /code> 从任意方法很容易:

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 操作:

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

但这只是丑陋的。

1:从技术上讲,我认为这更多的是对IDisposable的滥用,而不是使用。毕竟,我实际上确实想要一个try/finally - 这就是using给我的。但事实证明,我必须实现 IDisposable 才能获得 try/finally
不管怎样,我都同意。对我来说,语义相当清楚 - 如果您开始某事,我希望您也能完成某事。例如,如果您将“开始任务”消息写入日志文件,我也期望出现“结束任务”日志消息。我只是对“释放资源”的定义比大多数开发人员更具包容性。

Personally, I abuse1 using so much for this that I have a DisposeHelper class for this:

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

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

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

That lets me return an IDisposable from an arbitrary method quite easily:

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

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

You could also just do it inline:

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

Or, with the addition of an onInit Action:

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

but that's just ugly.

1: Technically, I suppose it's more of an abuse of IDisposable than it is of using. After all, I actually do want a try/finally - which is what using gives me. Turns out, though, that I have to implement IDisposable to get the try/finally.
Either way, I'm okay with it. The semantics are fairly clear to me - if you start something, I expect you to finish the something as well. Eg., if you write a "Beginning task" message to the log file, I expect a "Ending task" log message as well. I just have a more inclusive definition of "releasing resources" than most devs.

剩一世无双 2024-09-09 14:21:45

我知道 Visual Studio 的下一版本将大力推动这种灵活性。

在 .net 岩石上,Anders Hejlsberg 最近表示,下一个 Visual Studio 的主题之一发布(2012?)将是“编译器即服务”,从那时起,其他一些人暗示这将为语言扩展和与 DSL(领域特定语言)更紧密的集成打开很多大门。

现在,您实际上可以使用 DSL 做一些非常巧妙的事情,包括创建您自己的关键字,尽管在我看来这仍然有点尴尬。如果您有兴趣,请查看这篇关于在 Boo 中设计 DSL 的文章

这可能会让你有点震惊。

I understand there's going to be a big push towards that type of flexibility in the next version of Visual Studio.

On .net rocks, Anders Hejlsberg recently said that one of the main themes of the next Visual Studio release (2012?) will be "compiler as a service" and since then some other folks have hinted that this will open up a lot of doors for language extension and tighter integration with DSLs (Domain-Specific Languages).

Right now you can actually do some pretty neat stuff with DSLs including creating your own keywords, although it's still a little too awkward in my opinion. If you're interested, check out this article on designing DSLs in Boo.

It might blow your mind a little.

鹊巢 2024-09-09 14:21:45

魔法类:

// 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
}

The magical class:

// 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);
    }
}

Usage:

ReaderWriterLockSlim rwl = new ReaderWriterLockSlim();
using(rwl.Auto()) {
    // do stuff, locked
}
つ低調成傷 2024-09-09 14:21:45

我猜您会寻找预处理器指令,但 C# 不会不支持那些。最接近它的可能是Visual Studio snippets,您可以自己设计

I guess you would be looking for preprocessor directives, but C# doesn't support those. The closest to it might be Visual Studio snippets, which you can design yourself.

绮烟 2024-09-09 14:21:45

正如其他人已经说过的,IDisposable 可以被滥用来创建

As others have already said, IDisposable can be abused to create the notion of a scope in your code. It can even support nesting.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文