2010-05-21 123 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 
} 
相關問題