2010-05-21 13 views
8

Bạn sẽ đánh giá cao hai đường cú pháp sau:Tính năng này có tồn tại không? Xác định dấu ngoặc nhọn của riêng tôi trong 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() 
} 

Rõ ràng ví dụ đầu tiên trong mỗi trường hợp là dễ đọc hơn. Có cách nào để xác định loại điều này bản thân mình, hoặc trong ngôn ngữ C#, hoặc trong IDE? Lý do tôi hỏi là có rất nhiều cách sử dụng tương tự (của loại dài) có thể được hưởng lợi từ điều này, ví dụ như. nếu bạn đang sử dụng ReaderWriterLockSlim, bạn muốn một cái gì đó khá giống nhau.

EDIT 1:

Tôi đã yêu cầu cung cấp một ví dụ, vì vậy tôi sẽ cung cấp cho nó một đi:

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

Tất nhiên bạn sẽ phải đưa ra một số suy nghĩ như làm thế nào để sử dụng TryEnterReadLocks và những thứ như vậy với trả về. Nhưng tôi chắc chắn bạn có thể nghĩ ra điều gì đó.

+1

Bạn có thể mô phỏng một tải trọng của vật bằng cách sử dụng các nhà xây dựng là "pre-block" và Dispose() là "bài-block " chức năng. – Dykam

+0

Bạn có thể làm rõ ý bạn là gì? – Carlos

+0

ở đó bạn đi: http://stackoverflow.com/questions/2882983/does-this-feature-exist-defining-my-own-curly-brackets-in-c/2932023#2932023 – Dykam

Trả lời

19

Không chính xác, nhưng bạn có thể sử dụng một đại biểu hành động để có được một cái gì đó gần gũi:

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

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

Và sử dụng nó như thế này:

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 

Lưu ý rằng có một số hạn chế với điều này.Bạn không thể có một câu lệnh trả về có ý nghĩa bên trong các dấu ngoặc mới, ví dụ. Nhờ đóng cửa, bạn sẽ ít nhất vẫn có thể sử dụng các biến cục bộ.

+2

+1: Điều đó thực sự là khá tài giỏi. –

+0

Tôi thích điều này, tôi có thể cố gắng để viết này vào một lớp mở rộng cho tập quán rwlSlim của tôi. – Carlos

+0

Tôi sử dụng mẫu này rộng rãi và nó hoạt động thực sự tốt. Bạn có thể thực hiện các công cụ như 'T WithTry (Func func, T valueIfFails)' –

1

Không, không có cách nào để xác định từ khóa của riêng bạn. Chúng được định nghĩa bởi ngôn ngữ và được xây dựng trong trình biên dịch để giải thích cho IL. Chúng tôi chưa đạt đến mức trừu tượng đó!

Chỉ cần xem mức độ hào hứng của mọi người khi những thứ như vardynamic được giới thiệu.

Với ý nghĩ đó, hãy chỉnh sửa bài đăng của bạn để cho biết bạn muốn cú pháp nào cho ví dụ ReaderWriterLockSlim. Thật thú vị khi thấy.

5

Không may là không. Để hỗ trợ điều này, trình biên dịch C# cần phải mở rộng hơn cho người dùng cuối. Điều này sẽ bao gồm việc có thể xác định các từ khóa của riêng bạn và có hỗ trợ macro, v.v ...

Tuy nhiên những gì bạn có thể làm là xây dựng các phương pháp ít nhất có một chút cảm giác tương tự như thế này: (ví dụ về việc thực hiện lại) từ khóa khóa trong mã người dùng)

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

sử dụng sau đó sẽ là như thế này:

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

public void DoWork() 
{....} 

HOẶC

lockObject.WithinLock(DoWork); 

HOẶC

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

Tôi hiểu rằng sẽ có một sự thúc đẩy lớn đối với loại tính linh hoạt đó trong phiên bản tiếp theo của Visual Studio.

Trên đá .net, Anders Hejlsberg gần đây đã nói rằng một trong những chủ đề chính của bản phát hành Visual Studio tiếp theo (2012?) Sẽ là "trình biên dịch dưới dạng dịch vụ" và kể từ đó một số người khác đã gợi ý rằng điều này sẽ mở ra nhiều cửa cho phần mở rộng ngôn ngữ và tích hợp chặt chẽ hơn với DSL (Ngôn ngữ Cụ thể theo Miền).

Ngay bây giờ bạn có thể thực sự làm một số công cụ khá gọn gàng với DSL bao gồm tạo từ khóa của riêng bạn, mặc dù nó vẫn còn hơi khó xử trong quan điểm của tôi. Nếu bạn quan tâm, hãy xem this article on designing DSLs in Boo.

Nó có thể làm bạn suy nghĩ một chút.

3

Bạn không thể xác định cấu trúc như vậy trực tiếp, nhưng có nhiều cách để tạo ra các mẫu ngắn gọn tương tự:

Bạn có thể định nghĩa các lớp học thực hiện IDisposable để đóng gói loại này ngữ nghĩa sử dụng khối. Ví dụ, nếu bạn có một số lớp đóng gói một khóa ReaderWriterLockSlim (có được trên xây dựng, phát hành trên Vứt bỏ), bạn có thể tạo một thuộc tính trên lớp của bạn để tạo ra cá thể, kết quả theo cú pháp như sau:

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

Điều này được cho là lạm dụng IDisposable, nhưng mẫu này chắc chắn đã được sử dụng trong mã sản xuất.

Bạn có thể sử dụng lập trình hướng Aspect (với các công cụ như PostSharp) để bọc thân phương thức bằng logic nhập/xuất có thể tái sử dụng. Điều này thường được sử dụng để tiêm ghi nhật ký hoặc các mối quan tâm chéo khác mà bạn muốn áp dụng cho mã của mình mà không làm lộn xộn nó.

Bạn có thể viết các hàm lấy đại biểu làm tham số, sau đó kết thúc logic được ủy nhiệm trong một số cấu trúc tương tự. Ví dụ, đối với các ReaderWriterLockSlim một lần nữa, bạn có thể tạo ra một phương pháp như thế này:

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

này có thể khá mạnh mẽ, như hỗ trợ cho các biểu thức lambda với đóng cửa cho phép cho logic tùy tiện phức tạp mà không tự tạo ra các chức năng bao bọc và chuyển yêu cầu tham số trong các trường.

+0

Tôi nghĩ IDisposable chính xác cho các tài nguyên yêu cầu phát hành rõ ràng. Tại sao bạn nghĩ rằng không đúng sự thật của một khóa? –

+0

Cá nhân tôi nghĩ rằng đó là một cách sử dụng hợp lý của mô hình, nhưng có một sự khác biệt quan trọng. Hầu hết các lớp IDisposable cũng thực hiện một finalizer cho tài nguyên không được quản lý của họ, có nghĩa là các tài nguyên không được quản lý cuối cùng sẽ được phát hành. Nếu bạn không Dispose một đối tượng đang giữ một khóa thread cho đến khi Dispose được gọi, bạn có thể đã tạo bế tắc. Điều này được cho là nguy hiểm hơn. Ngoài ra còn có một trường hợp cực kỳ hiếm hoi trong .NET 3.5 và trước đó, Dispose sẽ không được gọi nếu một ThreadAbortException được ném vào đúng điểm. –

+0

Nhiều lớp IDisposable không trực tiếp giữ tài nguyên không được quản lý, vì vậy chúng không có finaliser.Ví dụ của bạn là hợp lý hơn bạn đề nghị. –

1

Không có tính năng gốc nào thực hiện những gì bạn muốn. Tuy nhiên, bạn có thể khai thác câu lệnh using chỉ bằng cách triển khai 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

Cá nhân, tôi lạm dụng using rất nhiều cho này mà tôi có một lớp DisposeHelper cho việc này:

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

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

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

đó cho phép tôi trở lại một IDisposable từ một phương pháp độc đoán khá dễ dàng:

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

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

Bạn cũng có thể thực hiện nội tuyến:

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

Hoặc, với việc bổ sung một hành động onInit:

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

nhưng đó chỉ là xấu xí.

: Về mặt kỹ thuật, tôi cho rằng đó là lạm dụng hơn IDisposable so với số using. Xét cho cùng, tôi thực sự là do muốn có một try/finally - đó là những gì using mang lại cho tôi. Hóa ra, mặc dù, tôi phải thực hiện IDisposable để có được try/finally. Dù bằng cách nào, tôi vẫn ổn với nó. Ngữ nghĩa khá rõ ràng đối với tôi - nếu bạn bắt đầu một cái gì đó, tôi hy vọng bạn cũng sẽ hoàn thành một cái gì đó. Ví dụ: nếu bạn viết thông báo "Bắt đầu tác vụ" vào tệp nhật ký, tôi cũng mong đợi thông báo nhật ký "Kết thúc nhiệm vụ". Tôi chỉ có một định nghĩa bao gồm hơn về "giải phóng tài nguyên" hơn hầu hết các nhà phát triển.

0

Như những người khác đã nói, IDisposable có thể bị lạm dụng để tạo notion of a scope trong mã của bạn. Nó thậm chí có thể hỗ trợ làm tổ.

1

Lớp huyền diệu:

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

Cách sử dụng:

ReaderWriterLockSlim rwl = new ReaderWriterLockSlim(); 
using(rwl.Auto()) { 
    // do stuff, locked 
} 
Các vấn đề liên quan