2012-12-10 41 views
7

Tôi đang dần dần nhận được đầu của tôi xung quanh các đại biểu, trong đó chữ ký của đại biểu phải phù hợp với phương pháp nó được ủy nhiệm quá.Làm thế nào để đại biểu từ khóa làm việc so với việc tạo một đại biểu

Tuy nhiên, vui lòng xem lại mã sau đây.

public static void Save() 
{ 
    ThreadStart threadStart = delegate 
    { 
     SaveToDatabase(); 
    }; 
    new Thread(threadStart).Start(); 
} 

private static void SaveToDatabase() { } 

bây giờ tôi đang bối rối vào thời điểm này, bởi vì các đại biểu trả void (vì đó là SaveToDatabase() là gì) nhưng, nó trở về rõ ràng một ThreadStart ... Hoặc là nó?

Nếu tôi viết đại biểu của chính mình, tôi sẽ không biết làm thế nào để đạt được điều này vì đại biểu sẽ phải vô hiệu để khớp với kiểu trả về là SaveToDatabase(). Nhưng nó không thể được; nó sẽ thuộc loại ThreadStart!

Câu hỏi của tôi là, tôi hoàn toàn hiểu sai hoặc điều này có thể được thực hiện bởi một số thủ thuật .NET không? Nếu tôi muốn viết phương pháp này nhưng tạo đại biểu của riêng tôi, tôi sẽ như thế nào?

+0

tại sao không 'ThreadStart threadStart = new ThreadStart (SaveToDatabase);' – Anirudha

+0

Tôi không nghĩ rằng bất cứ điều gì đang được trả lại vì không có từ khóa 'return'. Tôi nghĩ rằng một 'thread' mới đang được tạo ra sẽ thực thi phương thức được chỉ định bởi delegate. –

+0

@ Some1.Kill.The.DJ - nó sẽ thực sự, dài hạn, có một vài tham số. – Dave

Trả lời

4

Tôi bây giờ bối rối vào thời điểm này, bởi vì các đại biểu trả về void (như đó là những gì SaveToDatabase() là) nhưng, nó trở về rõ ràng một ThreadStart ... Hoặc là nó?

Nếu tôi đã đúng quyền đại biểu của riêng tôi, tôi sẽ không biết làm thế nào để đạt được điều này bởi vì các đại biểu sẽ phải vô hiệu để phù hợp với kiểu trả về của SaveToDatabase(), nhưng không thể vì nó sẽ là loại ThreadStart!

ThreadStart được định nghĩa là đại biểu. Thực tế, nó được định nghĩa là

public delegate void ThreadStart(); 

Vì vậy, mã của bạn không trả lại đại biểu hoặc ThreadStart. Nó chỉ đơn giản là xác định một hàm phù hợp với định nghĩa delegate ThreadStart. Nhà xây dựng Thread mong đợi một đại biểu ThreadStart, mà bạn đã xác định là biến số threadStart, trỏ đến hàm SaveToDatabase.

Tôi có xu hướng nghĩ về các đại biểu như cụm từ C++ cũ "hàm con trỏ". Các đại biểu cho phép chúng tôi xác định loại chức năng nào (các tham số và kiểu trả về) nên được chuyển thành tham số cho một hàm khác.

Câu hỏi của tôi là, tôi hoàn toàn hiểu sai hoặc điều này có thể thực hiện bởi một số thủ thuật .NET không? Nếu tôi muốn viết phương pháp này nhưng tạo đại biểu của riêng tôi, tôi sẽ như thế nào?

Tôi nghĩ bạn có thể đã hiểu lầm. Nhưng để trả lời câu hỏi này một cách cụ thể, phương thức bạn viết sẽ chỉ cần khớp với định nghĩa được chỉ định bởi kiểu ủy nhiệm, trong trường hợp này là ThreadStart. Định nghĩa phương thức đó phải trả lại void và không chấp nhận tham số nào.Phương thức SaveToDatabase của bạn khớp với loại ủy nhiệm này và do đó là phương thức ủy nhiệm thích hợp để tạo.

+0

Nó chỉ là một phương thức trả về void. Mã xây dựng ThreadStart() là một phương tiện để xây dựng mã con trỏ của đại biểu. Bạn có thể dễ dàng chỉ cần truyền tên phương thức phù hợp với kiểu ủy nhiệm ThreadStart vào constructor Thread. – villecoder

2

Khi bạn đang đi để chạy một tiến trình con administrated, phương pháp có nghĩa là sẽ được thực thi được đại diện bởi ThreadStart hoặc ParameterizedThreadStart, nhưng SaveToDatabasevoid và nó sẽ được thực hiện với void chữ ký, không phải với ThreadStart loại.

Ví dụ từ MSDN:

class Test 
{ 
    static void Main() 
    { 
     // To start a thread using a static thread procedure, use the 
     // class name and method name when you create the ThreadStart 
     // delegate. Beginning in version 2.0 of the .NET Framework, 
     // it is not necessary to create a delegate explicityly. 
     // Specify the name of the method in the Thread constructor, 
     // and the compiler selects the correct delegate. For example: 
     // 
     // Thread newThread = new Thread(Work.DoWork); 
     // 
     ThreadStart threadDelegate = new ThreadStart(Work.DoWork); 
     Thread newThread = new Thread(threadDelegate); 
     newThread.Start(); 

     // To start a thread using an instance method for the thread 
     // procedure, use the instance variable and method name when 
     // you create the ThreadStart delegate. Beginning in version 
     // 2.0 of the .NET Framework, the explicit delegate is not 
     // required. 
     // 
     Work w = new Work(); 
     w.Data = 42; 
     threadDelegate = new ThreadStart(w.DoMoreWork); 
     newThread = new Thread(threadDelegate); 
     newThread.Start(); 
    } 
} 

class Work 
{ 
    public static void DoWork() 
    { 
     Console.WriteLine("Static thread procedure."); 
    } 
    public int Data; 
    public void DoMoreWork() 
    { 
     Console.WriteLine("Instance thread procedure. Data={0}", Data); 
    } 
} 
+0

Vì vậy, nếu tôi đã tạo đại biểu của riêng mình, nó sẽ vẫn thuộc loại void? – Dave

+0

Bạn có thể tạo chức năng của riêng bạn. SaveToDatabase, SaveToDatabase2, SaveAgainToDatabase, nếu các phương thức đó bị vô hiệu, bạn có thể chuyển chúng đến constructor ThreadStart –

+0

Kiểm tra mẫu mã từ msdn mà tôi đã đăng. Nó có DoWork Trong lớp khác với void Chữ ký –

2

Từ MSDN

Một đại biểu chỉ là một loại tham chiếu đến một phương pháp. Khi một delegate được gán một method, nó sẽ hoạt động giống như phương thức đó. Phương pháp đại biểu có thể được sử dụng như bất kỳ phương pháp nào khác, với các thông số và giá trị trả về, như trong ví dụ này:

public delegate int PerformCalculation(int x, int y); 

Vì vậy, kiểu trả về của các đại biểu sẽ phù hợp với kiểu trả về của phương pháp đó được ủy thác.

Bất kỳ phương thức nào phù hợp với chữ ký của đại biểu, bao gồm loại trả về và thông số, có thể được chỉ định cho đại biểu. Điều này làm cho có thể thay đổi chương trình các cuộc gọi phương thức, và cũng có thể cắm mã mới vào các lớp hiện có. Miễn là bạn biết chữ ký của đại biểu, bạn có thể chỉ định phương thức được ủy nhiệm của riêng bạn.

5

Từ "đại biểu" bị lạm dụng một chút. Nó dễ dàng hơn với các lớp và các đối tượng. Một "lớp" giống như một kế hoạch chi tiết cho một đối tượng. Một "đối tượng" là một thực thể trong bộ nhớ, theo sau bản thiết kế của lớp.

Đối với đại biểu chúng tôi sử dụng cùng một từ, do đó tôi nghi ngờ sự nhầm lẫn của bạn. Hãy xem xét mã sau:

class Main 
{ 
    public delegate int DelegateType(string x); 
    public int SomeFunction(string y) { return int.Parse(y)*2; } 
    public void Main() 
    { 
     DelegateType delegateInstance = null; 
     delegateInstance = SomeFunction; 
     int z = delegateInstance("21"); 
     Console.WriteLine(z); 
    } 
} 

Mã này xuất ra "42".

DelegateType là loại đại biểu. Giống như một lớp học là một kế hoạch chi tiết cho một đối tượng, đại biểu là một kế hoạch chi tiết cho một hàm .

Vì vậy, sau này chúng tôi tạo biến có tên delegateInstance thuộc loại DelegateType. Với biến đó, chúng ta có thể gán hàm ANY lấy một tham số chuỗi đơn và trả về một số nguyên. Lưu ý rằng chúng tôi đã gán chức năng chính nó, không phải là kết quả của hàm đó. Nó giống như biến số delegateInstance bây giờ là một từ đồng nghĩa của hàm đó. Thật vậy, như đã trình bày một dòng sau, chúng ta có thể sử dụng delegateInstance để gọi funcion đó! Cũng giống như nếu delegateInstance là một chức năng. Nhưng, vì nó biến đổi, chúng ta cũng có thể làm tất cả những thứ tương tự mà chúng ta thường làm với các biến - như chuyển chúng thành các tham số cho các hàm khác, hoặc thậm chí trả về từ các hàm khác (Hàm trả về một hàm! !)

OK, chúng ta hãy xem mã đã khiến bạn bối rối.

public static void Save() 
{ 
    ThreadStart threadStart = delegate 
    { 
     SaveToDatabase(); 
    }; 
    new Thread(threadStart).Start(); 
} 

private static void SaveToDatabase() { } 

Điều đầu tiên cần lưu ý là bạn đã sử dụng anonymous delegate. Một sự lạm dụng thuật ngữ khác. Khi biên soạn, nó kết quả trong một cái gì đó như thế này:

public static void Save() 
{ 
    ThreadStart threadStart; 
    threadStart = __ASDASDASD6546549871; 
    var tmp = new Thread(threadStart); 
    tmp.Start(); 
} 

private static void SaveToDatabase() { } 

private void __ASDASDASD6546549871() 
{ 
    SaveToDatabase(); 
} 

Lưu ý rằng chức năng ẩn danh của bạn đã thực sự chuyển thành một chức năng hoàn toàn bình thường với một tên ngẫu nhiên, và sau đó chức năng được gán cho biến threadStart.

Vì vậy, bây giờ điều này giống như ví dụ trên.Chỉ cần thay thế DelegateType bằng ThreadStart, delegateInstance với threadStartSomeFunction với __ASDASDASD6546549871.

Bây giờ có ý nghĩa không?

+0

Điều này thực sự tốt - cảm ơn bạn rất nhiều vì đã dành thời gian của bạn để giải thích điều này, nó đã giúp rất nhiều. Cảm ơn bạn. – Dave

Các vấn đề liên quan