2010-05-21 122 views
8

定义我自己花括号中你会体会到以下两个语法糖:此功能是否存在?在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和这些类型的东西与返回。但我相信你可以想到一些事情。

+1

您可以通过使用构造称为“前块”和Dispose()方法为“后块模仿的东西负载“功能。 – Dykam 2010-05-21 14:48:24

+0

你能澄清你的意思吗? – Carlos 2010-05-21 15:04:04

+0

你去了:http://stackoverflow.com/questions/2882983/does-this-feature-exist-defining-my-own-curly-brackets-in-c/2932023#2932023 – Dykam 2010-05-28 19:50:13

回答

19

不完全是,但你可以使用一个动作代表获得了接近:

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 

注意,有与此有关的一些限制。例如,您不能在新的大括号中使用有意义的返回语句。由于关闭,你至少仍然可以使用局部变量。

+2

+1:这实际上很漂亮聪明。 – 2010-05-21 15:03:26

+0

我喜欢这一点,我可能会尝试写入扩展类为我的rwlSlim用法。 – Carlos 2010-05-23 10:17:51

+0

我广泛使用这种模式,它工作得很好。你可以做'T WithTry (Func func,T valueIfFail)' – 2010-05-28 19:59:09

1

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

只要看看如何引入vardynamic之类的东西,人人都会有多兴奋。

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

5

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

然而,你可以做的是构建方法,至少有一点类似的感觉,如: (重新实现然后使用在用户密码锁关键字)

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

会是这样:

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

public void DoWork() 
{....} 

OR

lockObject.WithinLock(DoWork); 

OR

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

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

On .net rocks,Anders Hejlsberg最近表示,下一个Visual Studio版本(2012?)的主要主题之一是“编译器即服务”,从那时起,其他一些人暗示说这会打开一个语言扩展和与DSL(域特定语言)更紧密集成的许多门户。

现在你可以用DSL做一些漂亮的东西,包括创建自己的关键字,尽管在我看来它仍然有点太尴尬。如果您有兴趣,请查看this article on designing DSLs in Boo

这可能会让你大跌眼镜。

3

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

可以定义实现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表达式支撑允许任意复杂的逻辑,而无需手动创建包装功能和通过所需参数在字段中。

+0

我认为IDisposable正好是需要显式释放的资源。你为什么认为这不是真的锁? – 2010-05-21 15:12:08

+0

我个人认为这是该模式的合理使用,但有一个重要的区别。大多数IDisposable类还为其非托管资源实现终结器,这意味着非托管资源最终将被释放。如果您无法处理持有线程锁的对象,直到调用Dispose,则可能会造成死锁。这可以说是更危险的。在.NET 3.5和更早的版本中,还有一种非常罕见的情况,如果在正确的位置抛出ThreadAbortException,Dispose将不会被调用。 – 2010-05-21 15:27:37

+0

许多IDisposable类不直接持有非托管资源,因此它们没有终结器。你的例子比你的建议更合理。 – 2010-10-15 17:13:27

1

没有原生功能可以做你想做的事。但是,只需执行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); 
    } 
    } 
} 
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很容易:

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

但是这只是丑陋。

:从技术上讲,我认为这更多的是IDisposable的滥用,而不是using。毕竟,我其实想要一个try/finally - 这是什么using给了我。原来,但是,我必须执行IDisposable才能获得try/finally。无论哪种方式,我都可以。语义对我来说是相当清楚的 - 如果你开始某事,我希望你完成东西以及。例如,如果您向日志文件写入“开始任务”消息,我也希望有一个“结束任务”日志消息。我只比“大多数开发者”有更全面的“释放资源”的定义。

0

正如其他人已经说过的,IDisposable可能会被滥用在您的代码中创建notion of a scope。它甚至可以支持嵌套。

1

神奇类:

// 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 
} 
相关问题