2011-07-07 26 views
5

Tôi mới dùng C# và không hiểu cú pháp gọi một hành động mới hoặc thậm chí là hành động là gì. Từ sự hiểu biết của tôi trong Port1_DataReceived, tôi phải tạo ra một hành động bởi vì tôi đang ở trong một tread mới ... Bất cứ ai có thể xây dựng trên lý do tại sao tôi cần phải làm điều này?Trợ giúp hiểu cú pháp C# khi gọi một Action mới

public Form1() 
{ 
    InitializeComponent(); 
    SerialPort Port1 = new SerialPort("COM11", 57600, Parity.None, 8, StopBits.One); 
    Port1.DataReceived += new SerialDataReceivedEventHandler(Port1_DataReceived); 
    Port1.Open(); 
} 


private void Port1_DataReceived(object sender, SerialDataReceivedEventArgs e) 
{ 
    SerialPort Port = (SerialPort)sender; 
    string Line = ""; 
    int BytestoRead = Port.BytesToRead; 
    Line = Port.ReadLine(); 
    label1.Invoke(new Action(() => 
    { 
      label1.Text = Line; 
     })); 
} 

Mã snip mà tôi đang thực sự gặp khó khăn trong sự hiểu biết là:

label1.Invoke(new Action(() => 
     { 
       label1.Text = Line; 
      })); 

Ai đó có thể phá vỡ điều này đang làm .. Tôi chắc chắn nó là không có gì để phức tạp, chỉ là tôi chưa bao giờ nhìn thấy bất cứ điều gì giống như nó trước đây. Cú pháp thực sự nắm giữ tôi là ()=> hành động mới đang trỏ đến mã bên dưới hoặc cái gì đó ??

Trả lời

7

Điều này sử dụng một cái gì đó được gọi là "biểu thức lambda" để tạo đại biểu ẩn danh khớp với chữ ký được mong đợi bởi hàm tạo Hành động.

Bạn có thể đạt được tác dụng tương tự như thế này:

label1.Invoke(SetText); 
... 
public void SetText() { label1.Text = Line; } 

hay như thế này:

label1.Invoke(new Action(SetText)); 
... 
public void SetText() { label1.Text = Line; } 

hay như thế này:

label1.Invoke(new Action(delegate() { label1.Text = Line; })); 

hay như thế này:

label1.Invoke(delegate() { label1.Text = Line; }); 

hay như thế này:

label1.Invoke(() => label1.Text = Line); 

Đây là chủ yếu chỉ các phím tắt cú pháp để làm cho nó dễ dàng hơn để đại diện cho một hành động.

Lưu ý rằng các biểu thức lambda thường có các tham số. Khi chỉ có một thông số, các dấu ngoặc đơn là tùy chọn:

list.ToDictionary(i => i.Key); 

Khi không có tham số hoặc nhiều thông số, dấu ngoặc đơn cần thiết để làm rõ điều bạn đang làm. Do đó, () =>.

0

Điều này tạo ra một phương thức ẩn danh (chính xác là lambda) và chuyển nó đến phương thức gọi. Lambdas là một cách tuyệt vời để có mã bạn chỉ cần một lần vì vậy bạn không cần nhiều phương thức trợ giúp chỉ làm một việc.

0

Điều này đảm bảo rằng văn bản của nhãn đang chạy trong chuỗi giao diện người dùng. Sự kiện Port1_DataReceived có thể sẽ chạy trong một chủ đề nền và giá trị văn bản của Nhãn không được đặt từ các chủ đề nền. Điều này ngăn cản điều đó xảy ra.

0

Tôi không biết nhãn1 là gì, nhưng có thể đọc như sau:

label1 là Hành động, nhận được một hành động khác làm thông số. Nó làm một cái gì đó và khi nó gọi hành động nhận được trong đối số.

Bây giờ, tôi đã đọc và tôi có thể là một vấn đề - label1 không thể là Hành động. Vì nó chỉ là một điều khiển được đặt ở đây: label1.Văn bản = Dòng;

Bạn gặp lỗi trong ứng dụng của mình;

EDIT

Xin lỗi, chỉ cần đọc rằng:

http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx

Thực thi các đại biểu xác định trên thread sở hữu cơ bản xử lý cửa sổ của tầm kiểm soát.

Mã là chính xác.

1

Nói chung khi bạn muốn thêm một cái gì đó cho bạn GUI và bạn đang làm việc từ một chủ đề khác, bạn cần phải làm một cái gì đó gọi là Invocation.

Để thực hiện invocation bạn sử dụng phương thức Controls Invoke hoặc phương thức như Application Dispatcher, các phương pháp này thường mất Action. An Action chỉ là những gì nó giống như âm thanh, một cái gì đó sẽ được thực hiện.

Trong trường hợp bạn đang làm là bạn muốn thêm một dòng văn bản vào một phần tử sống trên GUI của bạn, vì vậy những gì bạn cần làm là tạo một Action (phương pháp ẩn danh) và trong hành động này bạn chỉ cần nói "Thêm điều này vào Điều khiển của tôi". Và sau đó bạn Invoke điều này để tránh các vấn đề về luồng chéo.

()=> chỉ là một "lối tắt" (lambda way) để tạo phương thức, ẩn danh. Điều này có nghĩa là bạn không thể gọi điều này từ bất cứ nơi nào trừ ngữ cảnh của nơi bạn đã tạo phương thức ẩn danh.

Bạn cũng có thể Invoke một phương pháp "toàn cầu", nó không phải là một phương pháp ẩn danh.

1

Hành động là loại đại biểu, nói cách khác nó đóng gói một hàm. Cụ thể là một hành động đóng gói một hàm trả về void, trong khi ví dụ một Func sẽ đóng gói một hàm với một giá trị trả về. Đây là rất nhiều như một con trỏ hàm trong C++ - về cơ bản là một tham chiếu đến một hàm tức là một cách để đóng gói hành vi.

Phương thức .Invoke() nhận ủy nhiệm Hành động và chạy hàm mà nó trỏ đến. Trong trường hợp này, hàm mà nó trỏ đến là biểu thức lambda:

() => { label1.Text = Line } 

Dấu ngoặc đơn đầu tiên biểu thị mọi tham số được truyền vào hàm. Trong trường hợp này không có tham số để các dấu ngoặc đơn trống. Ví dụ: nếu bạn muốn chuyển vào hai chuỗi, bạn sẽ thực hiện:

var action = new Action<string, string>((x, y) => { // use x and y } 

Bất kể nội dung nào của hàm là '=>'. Bạn có quyền truy cập vào các biến được chỉ định trong dấu ngoặc đơn bên trong phạm vi của phần thân này.

Tổng cộng đây là một cách nhanh chóng để tạo ra một chức năng ẩn danh khi đang bay mà về cơ bản là tương đương như sau:

public void SetLine() 
{ 
    label1.Text = Line; 
} 

Như vậy bạn cũng có thể tạo đối tượng hành động bằng cách thực hiện:

var action = new Action(SetLine) 

nơi bạn đang đi qua trong tên của phương pháp để đóng gói thay vì đi qua trong một lambda. Những gì được truyền vào được gọi là 'Nhóm phương pháp'.

0

Hành động là đại biểu. Label1.Invoke() đang được sử dụng để thực thi mã label1.Text = line để tránh Cross Threading Operation. trình xử lý sự kiện cho sự kiện DataReceived đang thực hiện trên một luồng khác với luồng UI. label1.Invoke() sẽ thực thi mã trong chuỗi giao diện người dùng.

5

Hãy chia nhỏ từng mảnh một.

label1.Invoke(

Đây là phương pháp Control.Invoke. Đây là cách nó được định nghĩa:

public Object Invoke(Delegate method); 

Thực thi các đại biểu xác định trên thread sở hữu cơ bản xử lý cửa sổ của tầm kiểm soát.

Điều đó có nghĩa là bạn cung cấp cho nó một tham chiếu đến một phương pháp để gọi, và Control.Invoke sẽ chắc chắn rằng nó được gọi trên thread UI (mà sẽ ngăn chặn trường hợp ngoại lệ cross-threading khi cập nhật giao diện người dùng.) Phải mất một tham số mặc định là Delegate, có nghĩa là bạn cần chuyển cho nó một phương thức không có tham số và không có giá trị trả lại. Đó là nơi mà các loại System.Action đại biểu do thỏa thuận hợp:

public delegate void Action(); 

Sử dụng biểu thức lambda, chúng ta có thể tạo ra một inline Action đại biểu. Trước tiên, chúng tôi chỉ định loại đại biểu:

label1.Invoke(new Action(

Sau đó, chúng tôi sẽ bắt đầu cú pháp lambda. Một tập rỗng của ngoặc sẽ biểu thị rằng các chức năng lambda mất không tham số, và một "mũi tên" sau đó cho thấy rằng chúng tôi muốn bắt đầu phương pháp:

label1.Invoke(new Action(() => 

Bây giờ, vì phương pháp lambda không có giá trị trả về (nhưng phải thực hiện một tuyên bố), chúng tôi cần phải bao quanh mã chúng tôi muốn thực hiện trên thread UI trong dấu ngoặc nhọn:

label1.Invoke(new Action(() => 
{ 
    label1.Text = Line; 
} 

Đóng lên ngoặc còn lại, và bạn có đầy đủ, tuyên bố đã hoàn thành.

label1.Invoke(new Action(() => 
{ 
    label1.Text = Line; 
})); 
Các vấn đề liên quan