test

test

2010年3月31日 星期三

MessageBox-使用訊息對話方塊

●The MessageBox function creates, displays, and operates a message box. The message box contains an application-defined message and title, plus any combination of predefined icons and push buttons.

●VB6建議宣告法: Declare Function MessageBox Lib "user32" Alias "MessageBoxA" (ByVal hwnd As Long, ByVal lpText As String, ByVal lpCaption As String, ByVal wType As Long) As Long
VB2008宣告法: Declare Function MessageBox Lib "user32" Alias "MessageBoxA" (ByVal hwnd As Integer, ByVal lpText As String, ByVal lpCaption As String, ByVal wType As Integer) As Integer

●用法
VB6:
傳回值 = MessageBox(擁有者的handle, "要顯示的文字", "視窗抬頭", 視窗種類)
Private Sub COmmand1_Click()
Dim Rtvl As Ling
Rtvl = MessageBox(Me.hWnd, "你好嗎?", "問候", 32 OR 4)
End Sub


VB2008:
Public Class Form1

Private Declare Function MessageBox Lib "user32" Alias "MessageBoxA" (ByVal hWnd As Integer, ByVal lpText As String, ByVal lpCaption As String, ByVal wType As Integer) As Integer

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim rtl As Integer = MessageBox(Me.Handle, "開始學習Windows編程", "訊息對話框", 32 Or 4)
MsgBox(rtl)
End Sub
End Class


VC++:
#include <windows.h>

#pragma comment (lib, "User32.lib")

int WinMain(
HINSTANCE hInstance,
HINSTANCE hPreInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
MessageBox(NULL,
TEXT("開始學習Windows編程"),
TEXT("訊息對話框"),
MB_OK);
return 0;
}


視窗種類 = 按鈕種類 OR 圖示種類

按鈕種類
1 確定、取消
2 異常終止、重試、略過
3 是、否、取消
4 是、否
5 重試、取消
6 說明(無法關閉)
7 無按鈕(無法關閉)
8 取消、說明
9 無按鈕(無法關閉)
10 確定、取消、說明
11 無按鈕(無法關閉)
12 說明、確定、取消、說明
13 無按鈕(無法關閉)
14 確定、取消、說明、異常終止、取消

圖示種類
0 第一個按鈕為預設
16 叉叉
32 問號
48 驚嘆號
64 資訊
256 第二個按鈕為預設
512 第三個按鈕為預設

傳回值代表按下那個按鈕
1 確定
2 取消
3 中斷
4 重試
5 忽略
6 是
7 否

●VB也提供了MsgBox函數,兩者執行來最大的差別是,一樣都是視窗動結,然而MsgBox會使得整個程式停止,等待使用者結束MessageBox的使用,而MessageBox函數則只會凍結視窗而不會終止程式的執行。

MSDN:
MessageBox Function

--------------------------------------------------------------------------------

The MessageBox function creates, displays, and operates a message box. The message box contains an application-defined message and title, along with any combination of predefined icons and push buttons.


Syntax


int MessageBox( HWND hWnd,
LPCTSTR lpText,
LPCTSTR lpCaption,
UINT uType
);
Parameters


hWnd
[in] Handle to the owner window of the message box to be created. If this parameter is NULL, the message box has no owner window.
lpText
[in] Pointer to a null-terminated string that contains the message to be displayed.
lpCaption
[in] Pointer to a null-terminated string that contains the dialog box title. If this parameter is NULL, the default title Error is used.
uType
[in] Specifies the contents and behavior of the dialog box. This parameter can be a combination of flags from the following groups of flags.


To indicate the buttons displayed in the message box, specify one of the following values.


MB_ABORTRETRYIGNORE (0x00000002L)
The message box contains three push buttons: Abort, Retry, and Ignore.
MB_CANCELTRYCONTINUE (0x00000006L)
Microsoft Windows 2000/XP: The message box contains three push buttons: Cancel, Try Again, Continue. Use this message box type instead of MB_ABORTRETRYIGNORE.
MB_HELP (0x00004000L)
Windows 95/98/Me, Windows NT 4.0 and later: Adds a Help button to the message box. When the user clicks the Help button or presses F1, the system sends a WM_HELP message to the owner.
MB_OK (0x00000000L)
The message box contains one push button: OK. This is the default.
MB_OKCANCEL (0x00000001L)
The message box contains two push buttons: OK and Cancel.
MB_RETRYCANCEL (0x00000005L)
The message box contains two push buttons: Retry and Cancel.
MB_YESNO (0x00000004L)
The message box contains two push buttons: Yes and No.
MB_YESNOCANCEL (0x00000003L)
The message box contains three push buttons: Yes, No, and Cancel.
To display an icon in the message box, specify one of the following values.
MB_ICONEXCLAMATION (0x00000030L)
An exclamation-point icon appears in the message box.
MB_ICONWARNING (MB_ICONEXCLAMATION)
An exclamation-point icon appears in the message box.
MB_ICONINFORMATION (MB_ICONASTERISK)
An icon consisting of a lowercase letter i in a circle appears in the message box.
MB_ICONASTERISK (0x00000040L)
An icon consisting of a lowercase letter i in a circle appears in the message box.
MB_ICONQUESTION (0x00000020L)
A question-mark icon appears in the message box. The question-mark message icon is no longer recommended because it does not clearly represent a specific type of message and because the phrasing of a message as a question could apply to any message type. In addition, users can confuse the message symbol question mark with Help information. Therefore, do not use this question mark message symbol in your message boxes. The system continues to support its inclusion only for backward compatibility.
MB_ICONSTOP (MB_ICONHAND)
A stop-sign icon appears in the message box.
MB_ICONERROR (MB_ICONHAND)
A stop-sign icon appears in the message box.
MB_ICONHAND (0x00000010L)
A stop-sign icon appears in the message box.
To indicate the default button, specify one of the following values.
MB_DEFBUTTON1 (0x00000000L)
The first button is the default button.
MB_DEFBUTTON1 is the default unless MB_DEFBUTTON2, MB_DEFBUTTON3, or MB_DEFBUTTON4 is specified.

MB_DEFBUTTON2 (0x00000100L)
The second button is the default button.
MB_DEFBUTTON3 (0x00000200L)
The third button is the default button.
MB_DEFBUTTON4 (0x00000300L)
The fourth button is the default button.
To indicate the modality of the dialog box, specify one of the following values.
MB_APPLMODAL (0x00000000L)
The user must respond to the message box before continuing work in the window identified by the hWnd parameter. However, the user can move to the windows of other threads and work in those windows.
Depending on the hierarchy of windows in the application, the user may be able to move to other windows within the thread. All child windows of the parent of the message box are automatically disabled, but pop-up windows are not.

MB_APPLMODAL is the default if neither MB_SYSTEMMODAL nor MB_TASKMODAL is specified.

MB_SYSTEMMODAL (0x00001000L)
Same as MB_APPLMODAL except that the message box has the WS_EX_TOPMOST style. Use system-modal message boxes to notify the user of serious, potentially damaging errors that require immediate attention (for example, running out of memory). This flag has no effect on the user's ability to interact with windows other than those associated with hWnd.
MB_TASKMODAL (0x00002000L)
Same as MB_APPLMODAL except that all the top-level windows belonging to the current thread are disabled if the hWnd parameter is NULL. Use this flag when the calling application or library does not have a window handle available but still needs to prevent input to other windows in the calling thread without suspending other threads.
To specify other options, use one or more of the following values.
MB_DEFAULT_DESKTOP_ONLY (0x00020000L)
Windows NT/2000/XP: Same as desktop of the interactive window station. For more information, see Window Stations.
Windows NT 4.0 and earlier: If the current input desktop is not the default desktop, MessageBox fails.


Windows 2000/XP: If the current input desktop is not the default desktop, MessageBox does not return until the user switches to the default desktop.


Windows 95/98/Me: This flag has no effect.


MB_RIGHT (0x00080000L)
The text is right-justified.
MB_RTLREADING (0x00100000L)
Displays message and caption text using right-to-left reading order on Hebrew and Arabic systems.
MB_SETFOREGROUND (0x00010000L)
The message box becomes the foreground window. Internally, the system calls the SetForegroundWindow function for the message box.
MB_TOPMOST (0x00040000L)
The message box is created with the WS_EX_TOPMOST window style.
MB_SERVICE_NOTIFICATION (0x00200000L)
Windows NT/2000/XP: The caller is a service notifying the user of an event. The function displays a message box on the current active desktop, even if there is no user logged on to the computer.
Terminal Services: If the calling thread has an impersonation token, the function directs the message box to the session specified in the impersonation token.


If this flag is set, the hWnd parameter must be NULL. This is so that the message box can appear on a desktop other than the desktop corresponding to the hWnd.

For more information on the changes between Microsoft Windows NT 3.51 and Windows NT 4.0, see Remarks.

For information on security considerations in regard to using this flag, see Interactive Services.


MB_SERVICE_NOTIFICATION_NT3X (0x00040000L)
Windows NT/2000/XP: This value corresponds to the value defined for MB_SERVICE_NOTIFICATION for Windows NT version 3.51.
For more information on the changes between Windows NT 3.51 and Windows NT 4.0, see Remarks.

Return Value


If a message box has a Cancel button, the function returns the IDCANCEL value if either the ESC key is pressed or the Cancel button is selected. If the message box has no Cancel button, pressing ESC has no effect.


If the function fails, the return value is zero. To get extended error information, call GetLastError.


If the function succeeds, the return value is one of the following menu-item values.


IDABORT (3) Abort button was selected.
IDCANCEL (2) Cancel button was selected.
IDCONTINUE (11) Continue button was selected.
IDIGNORE (5) Ignore button was selected.
IDNO (7) No button was selected.
IDOK (1) OK button was selected.
IDRETRY (4) Retry button was selected.
IDTRYAGAIN (10) Try Again button was selected.
IDYES (6) Yes button was selected.



Remarks

Adding two right-to-left marks (RLMs), represented by Unicode formatting character U+200F, in the beginning of a MessageBox display string is interpreted by the Win32 MessageBox rendering engine so as to cause the reading order of the MessageBox to be rendered as right-to-left (RTL).

When you use a system-modal message box to indicate that the system is low on memory, the strings pointed to by the lpText and lpCaption parameters should not be taken from a resource file because an attempt to load the resource may fail.

If you create a message box while a dialog box is present, use a handle to the dialog box as the hWnd parameter. The hWnd parameter should not identify a child window, such as a control in a dialog box.

Windows 95/98/Me: The system can support a maximum of 16,364 window handles.

Windows NT/2000/XP: The value of MB_SERVICE_NOTIFICATION changed starting with Windows NT 4.0. Windows NT 4.0 provides backward compatibility for preexisting services by mapping the old value to the new value in the implementation of MessageBox. This mapping is done only for executables that have a version number earlier than 4.0, as set by the linker.

To build a service that uses MB_SERVICE_NOTIFICATION and can run on both Microsoft Windows NT 3.x and Windows NT 4.0, you can do one of the following.


At link-time, specify a version number less than 4.0.
At link-time, specify version 4.0. At run-time, use the GetVersionEx function to check the system version. Then, when running on Windows NT 3.x, use MB_SERVICE_NOTIFICATION_NT3X; and on Windows NT 4.0, use MB_SERVICE_NOTIFICATION.

Windows 95/98/Me: Even though MessageBoxW exists, it is supported by the Microsoft Layer for Unicode on Windows 95/98/Me Systems to give more consistent behavior across all Windows operating systems.


Example

For an example, see Displaying a Message Box.

Function Information

Minimum DLL Version user32.dll
Header Declared in Winuser.h, include Windows.h
Import library User32.lib
Minimum operating systems Windows 95, Windows NT 3.1
Unicode Implemented as ANSI and Unicode versions.



WinUser.h中之宣告:

/*
* MessageBox() Flags
*/
#define MB_OK 0x00000000L
#define MB_OKCANCEL 0x00000001L
#define MB_ABORTRETRYIGNORE 0x00000002L
#define MB_YESNOCANCEL 0x00000003L
#define MB_YESNO 0x00000004L
#define MB_RETRYCANCEL 0x00000005L
#if(WINVER >= 0x0500)
#define MB_CANCELTRYCONTINUE 0x00000006L
#endif /* WINVER >= 0x0500 */


#define MB_ICONHAND 0x00000010L
#define MB_ICONQUESTION 0x00000020L
#define MB_ICONEXCLAMATION 0x00000030L
#define MB_ICONASTERISK 0x00000040L

#if(WINVER >= 0x0400)
#define MB_USERICON 0x00000080L
#define MB_ICONWARNING MB_ICONEXCLAMATION
#define MB_ICONERROR MB_ICONHAND
#endif /* WINVER >= 0x0400 */

#define MB_ICONINFORMATION MB_ICONASTERISK
#define MB_ICONSTOP MB_ICONHAND

#define MB_DEFBUTTON1 0x00000000L
#define MB_DEFBUTTON2 0x00000100L
#define MB_DEFBUTTON3 0x00000200L
#if(WINVER >= 0x0400)
#define MB_DEFBUTTON4 0x00000300L
#endif /* WINVER >= 0x0400 */

#define MB_APPLMODAL 0x00000000L
#define MB_SYSTEMMODAL 0x00001000L
#define MB_TASKMODAL 0x00002000L
#if(WINVER >= 0x0400)
#define MB_HELP 0x00004000L // Help Button
#endif /* WINVER >= 0x0400 */

#define MB_NOFOCUS 0x00008000L
#define MB_SETFOREGROUND 0x00010000L
#define MB_DEFAULT_DESKTOP_ONLY 0x00020000L

#if(WINVER >= 0x0400)
#define MB_TOPMOST 0x00040000L
#define MB_RIGHT 0x00080000L
#define MB_RTLREADING 0x00100000L


#endif /* WINVER >= 0x0400 */

#ifdef _WIN32_WINNT
#if (_WIN32_WINNT >= 0x0400)
#define MB_SERVICE_NOTIFICATION 0x00200000L
#else
#define MB_SERVICE_NOTIFICATION 0x00040000L
#endif
#define MB_SERVICE_NOTIFICATION_NT3X 0x00040000L
#endif

#define MB_TYPEMASK 0x0000000FL
#define MB_ICONMASK 0x000000F0L
#define MB_DEFMASK 0x00000F00L
#define MB_MODEMASK 0x00003000L
#define MB_MISCMASK 0x0000C000L


/*
* Dialog Box Command IDs
*/
#define IDOK 1
#define IDCANCEL 2
#define IDABORT 3
#define IDRETRY 4
#define IDIGNORE 5
#define IDYES 6
#define IDNO 7
#if(WINVER >= 0x0400)
#define IDCLOSE 8
#define IDHELP 9
#endif /* WINVER >= 0x0400 */

#if(WINVER >= 0x0500)
#define IDTRYAGAIN 10
#define IDCONTINUE 11
#endif /* WINVER >= 0x0500 */

#if(WINVER >= 0x0501)
#ifndef IDTIMEOUT
#define IDTIMEOUT 32000
#endif
#endif /* WINVER >= 0x0501 */

2008年5月2日 星期五

LINQ之基礎-Lambda運算式

以下為C#之程式(主控台應用程式專案):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Program pg = new Program();
helloDelegate myHelloDelegate = new helloDelegate(pg.ReturnMessage);
string message = myHelloDelegate("Kangting");
Console.WriteLine(message);
Console.ReadKey();
}

public string ReturnMessage(string pName)
{
string message = "Hello,";
message += pName;
return message;
}

public delegate string helloDelegate(string pName);
}
}

我將之改寫成VB2008之程式碼(主控台應用程式專案):
Module Module1

Public Delegate Function helloDelegate(ByVal pName As String) As String

Public Function ReturnMessage(ByVal pName As String) As String
Dim message As String = "Hello,"
message &= pName
Return message
End Function

Sub Main()
Dim myHelloDelegate As New helloDelegate(AddressOf ReturnMessage)
Dim message As String = myHelloDelegate.Invoke("Kangting")
Console.WriteLine(message)
Console.ReadKey()
End Sub

End Module

再進一步將之改寫為:
Module Module1

Public Delegate Function helloDelegate(ByVal pName As String) As String

Public Function ReturnMessage(ByVal pName As String) As String
Dim message As String = "Hello,"
message &= pName
Return message
End Function

Sub Main()
'Dim myHelloDelegate As New helloDelegate(AddressOf ReturnMessage)
'Dim message As String = myHelloDelegate.Invoke("Kangting")
'Console.WriteLine(message)
Dim myHelloDelegate As helloDelegate = Function(pName As String) "Hello," & pName
Console.WriteLine(myHelloDelegate("Kangting"))
Console.ReadKey()
End Sub

End Module

2008年4月23日 星期三

LINQ運算式基本構成子句-Sub-Statement

一、指定資料來源(From):這是LINQ查詢的第一步,From子句一定排在最前面。它可指定一個或多個範圍變數以及要查詢的集合。
From element [ As type ] In collection [ _ ]
[, element2 [ As type2 ] In collection2 [, ... ] ]

其中,element及collection為必要項,type則為選擇項。

  • element:用於逐一查看集合中項目的「範圍變數」(Range Variable)。在查詢逐一查看 collection 時,範圍變數可用以參考 collection 的每個成員。必須是可列舉的型別。
  • type:element 的型別。如果沒有指定 type,則會從 collection 推斷 element 的型別。
  • collection:參考要查詢的集合。必須是可列舉的型別。
可以在查詢中指定多個From子句,也可以在單一From子句中將每個相關的範圍變數和集合以逗號隔開,藉以指定多個範圍變數和集合。這兩種寫法如下:
' Multiple From clauses in a query.
Dim result = From var1 In collection1, var2 In collection2

' Equivalent syntax with a single From clause.
Dim result2 = From var1 In collection1 _
From var2 In collection2
也可以組成一個巢狀From子句,其中第二個子句中的集合是根據第一個子句中的範圍變數屬性:
Dim allOrders = From cust In GetCustomerList() _
From ord In cust.Orders _
Select ord

二、篩選資料(Where):Where子句會用來執行篩選,而查詢接著只會傳回運算式為true的項目。可以使用邏輯運算子(如And、Or、AndAlso、OrElse、Is 和 IsNot)來合併Where子句中的篩選條件運算式。

From element [ As type ] In collection [ _ ]
[, element2 [ As type2 ] In collection2 [, ... ] ]
Where condition
  • condition:為必要項。是個運算式,用於判斷集合中目前項目的值是否要納入輸出集合。此運算式必須評估為Boolean值或Boolean值的對等用法。如果條件評估為True,則會將項目納入查詢結果中,否則會將項目排除在查詢結果之外。
可以在 Where 子句中呼叫函式,以對集合中目前項目的值執行計算或作業。在 Where 子句中呼叫函式會使查詢在進行定義時就立即執行,而不是等到進行存取時才執行。

三、排序資料(Order By): Order By子句會根據指定的一個或多個欄位來排序所傳回序列中的項目。

From element [ As type ] In collection [ _ ]
[, element2 [ As type2 ] In collection2 [, ... ] ]
Where condition
Order By orderExp1 [ Ascending Descending ] [, orderExp2 [...] ]
  • orderExp1
    為必要項。目前查詢結果的一個或多個欄位,用以識別如何排序傳回的值。欄位名稱必須以逗號(,)分隔。可以使用Ascending或Descending關鍵字,將每個欄位識別為以遞增或遞減順序排序。如果未指定Ascending或Descending關鍵字,預設排序次序是遞增排序。排序次序欄位優先順序是由左至右。
Order By 子句只能根據目前範圍 (Scope) 的範圍 (Range) 變數排序結果。例如,Select 子句在查詢運算式中引入新的範圍 (Scope),並用新的反覆運算變數代表該範圍 (Scope)。在查詢中 Select 子句之前定義的範圍 (Range) 變數在 Select 子句之後就無法使用。因此,如果您要依 Select 子句中無法使用的欄位排序結果,就必須將 Order By 子句放在 Select 子句前面。您必須這麼做的其中一個範例就是依不在傳回結果中的欄位來排序查詢時。

四、選取資料(Select):Select子句會指定所傳回項目的格式和內容。

From element [ As type ] In collection [ _ ]
[, element2 [ As type2 ] In collection2 [, ... ] ]
Where condition
Order By orderExp1 [ Ascending Descending ] [, orderExp2 [...] ]
Select [ var1 = ] fieldName1 [, [ var2 = ] fieldName2 [...] ]
  • var1:選擇項,可用於參考資料行運算式之結果的別名 (Alias)
  • fieldName1:必要項。在查詢結果中傳回的欄位名稱
查詢不一定需要Select子句。如果未指定Select子句,查詢會依據目前範圍所識別之範圍變數的所有成員傳回型別。
Select子句可以參考目前範圍中的任何變數。這包含From子句中識別的範圍變數,也包含由Aggregate、Let、Group By或Group Join子句之別名所建立的新變數,或由查詢運算式中先前Select子句所決定的變數。

若要擷取包含完整 Customer 物件的集合,請選取範圍變數本身:
Dim londonCusts2 = From cust In customers _
Where cust.City = "London" _
Order By cust.Name Ascending _
Select cust

如果 Customer 執行個體 (Instance) 是擁有多個欄位的大型物件,而您只要擷取名稱,則可以選取 cust.Name (如下列範例所示)。區域型別推斷會知道要將結果的型別從 Customer 物件的集合變更為字串的集合。
Dim londonCusts3 = From cust In customers _
Where cust.City = "London" _
Order By cust.Name Ascending _
Select cust.Name

若要選取資料來源中的多個欄位,您有兩個選擇:

  • 在 Select 子句中,指定想要併入結果中的欄位。編譯器會在定義匿名型別時,將那些欄位當成該型別的屬性。
    因為在下列範例中傳回的項目是匿名型別執行個體,所以無法在程式碼的別處依名稱來參考該型別。編譯器指定的型別名稱會包含一般 Visual Basic 程式碼中無效的字元。在下列範例中,由 londonCusts4 內的查詢所傳回之集合中的項目會是匿名型別執行個體。
    Dim londonCusts4 = From cust In customers _
    Where cust.City = "London" _
    Order By cust.Name Ascending _
    Select Name = cust.Name, Phone = cust.Phone

    For Each londonCust In londonCusts4
    Console.WriteLine(londonCust.Name & " " & londonCust.Phone)
    Next
  • 定義具名型別並使其內含想要併入結果中的特定欄位,然後在 Select 子句中建立和初始化該型別的執行個體。只有當必須在包含所傳回結果的集合外部使用個別結果,或者必須在方法呼叫中將個別結果當成參數傳遞時,才使用這個選項。下列範例中 londonCusts5 的型別是 IEnumerable(Of NamePhone)。
    Public Class NamePhone
    Public Name As String
    Public Phone As String
    ' Additional class elements
    End Class

    Dim londonCusts5 = From cust In customers _
    Where cust.City = "London" _
    Order By cust.Name Ascending _
    Select New NamePhone With {.Name = cust.Name, _
    .Phone = cust.Phone}

Select子句也可以包含靜態值。例如,下列程式碼範例會顯示查詢運算式,其中 Select 子句會將查詢結果定義為匿名型別並具有四個成員:ProductName、Price、Discount 及 DiscountedPrice。ProductName 和 Price 成員值是取自 From 子句中定義的產品範圍變數。DiscountedPrice 成員值是在 Let 子句中計算。Discount 成員是靜態值。
' 10% discount
Dim discount_10 = 0.1
Dim priceList = _
From product In products _
Let DiscountedPrice = product.UnitPrice * (1 - discount_10) _
Select product.ProductName, Price = product.UnitPrice, _
Discount = discount_10, DiscountedPrice

Select 子句會引入新的範圍變數集供後續查詢子句使用,範圍中不再有先前的範圍變數。查詢運算式中最後一個 Select 子句會決定查詢的傳回值。例如,下列查詢會傳回總值超過 500 的每份客戶訂單的公司名稱和訂單 ID。第一個 Select 子句識別 Where 子句和第二個 Select 子句的範圍變數。第二個 Select 子句識別查詢傳回的值,做為新匿名型別。
Dim customerList = From cust In customers, ord In cust.Orders _
Select Name = cust.CompanyName, _
Total = ord.Total, ord.OrderID _
Where Total > 500 _
Select Name, OrderID

如果 Select 子句識別單一項目以傳回,則查詢運算式會傳回該單一項目之型別的集合。如果 Select 子句識別多個項目以傳回,則查詢運算式會依據選取的項目傳回新匿名型別的集合。例如,下列兩個查詢會依據 Select 子句傳回兩個不同型別的集合。第一個查詢會以字串傳回公司名稱集合。第二個查詢會傳回以公司名稱和地址資訊填入 (Populate) 之 Customer 物件的集合。
Dim customerNames = From cust In customers _
Select cust.CompanyName

Dim customerInfo As IEnumerable(Of Customer) = _
From cust In customers _
Select New Customer With {.CompanyName = cust.CompanyName, _
.Address = cust.Address, _
.City = cust.City, _
.Region = cust.Region, _
.Country = cust.Country}

五、聯結資料(Join 和 Group Join)
Join 關鍵字相當於 SQL 中的 INNER JOIN。它會根據兩個集合中項目的相符索引鍵值來合併兩個集合。
Join element In collection _
[ joinClause _ ]
[ groupJoinClause ... _ ]
On key1 Equals key2 [ And key3 Equals key4 [... ]
  • element:必要項。代表要聯結之集合的控制項變數。
  • collection:必要項。要與 Join 運算子左邊定義的集合進行合併的集合。Join 子句可以巢狀於另一個 Join 子句或 Group Join 子句中。
  • joinClause:選擇項,一個或多個用來進一步限定查詢的其他 Join 子句。
  • groupJoinClause:選擇項,一個或多個用來進一步限定查詢的其他 Group Join 子句。
  • key1 Equals key2:必要項。識別要聯結之集合的索引鍵。您必須使用 Equals 運算子來比較要聯結之集合中的索引鍵。若要識別多個索引鍵,您可以使用 And 運算子來合併聯結條件。key1 必須來自 Join 運算子左邊的集合,而 key2 必須來自 Join 運算子右邊的集合。

    聯結條件中使用的索引鍵,可以是包含集合中之多個項目的運算式。不過,每個索引鍵運算式只能包含其針對之集合中的項目。
可以執行隱含聯結 (Implicit Join) 來合併集合,而不需要使用 Join 子句。其做法是在 From 子句中加入多個 In 子句,然後指定 Where 子句以識別要使用的聯結索引鍵。
Dim customerIDs() = {"ALFKI", "VICTE", "BLAUS", "TRAIH"}

Dim customerList = From cust In customers, custID In customerIDs _
Where cust.CustomerID = custID _
Select cust.CompanyName

下列程式碼範例會使用 Join 子句聯結兩個集合。
Imports System.Diagnostics

Public Class JoinSample

Public Sub ListProcesses()
Dim processDescriptions As New List(Of ProcessDescription)
processDescriptions.Add(New ProcessDescription _
With {.ProcessName = "explorer", _
.Description = "Windows Explorer"})
processDescriptions.Add(New ProcessDescription _
With {.ProcessName = "winlogon", _
.Description = "Windows Logon"})
processDescriptions.Add(New ProcessDescription _
With {.ProcessName = "cmd", _
.Description = "Command Window"})
processDescriptions.Add(New ProcessDescription _
With {.ProcessName = "iexplore", _
.Description = "Internet Explorer"})

Dim processes = From proc In Process.GetProcesses _
Join desc In processDescriptions _
On proc.ProcessName Equals desc.ProcessName _
Select proc.ProcessName, proc.Id, desc.Description

For Each proc In processes
Console.WriteLine("{0} ({1}), {2}", _
proc.ProcessName, proc.Id, proc.Description)
Next
End Sub

End Class

Public Class ProcessDescription
Public ProcessName As String
Public Description As String
End Class

下列程式碼範例會使用 Join 子句並搭配兩個索引鍵資料行聯結兩個集合。
Imports System.Diagnostics

Public Class JoinSample2

Public Sub ListProcesses()
Dim processDescriptions As New List(Of ProcessDescription2)

' 8 = Normal priority, 13 = High priority
processDescriptions.Add(New ProcessDescription2 _
With {.ProcessName = "explorer", _
.Description = "Windows Explorer", _
.Priority = 8})
processDescriptions.Add(New ProcessDescription2 _
With {.ProcessName = "winlogon", _
.Description = "Windows Logon", _
.Priority = 13})
processDescriptions.Add(New ProcessDescription2 _
With {.ProcessName = "cmd", _
.Description = "Command Window", _
.Priority = 8})
processDescriptions.Add(New ProcessDescription2 _
With {.ProcessName = "iexplore", _
.Description = "Internet Explorer", _
.Priority = 8})

Dim processes = From proc In Process.GetProcesses _
Join desc In processDescriptions _
On proc.ProcessName Equals desc.ProcessName _
And proc.BasePriority Equals desc.Priority _
Select proc.ProcessName, proc.Id, desc.Description, _
desc.Priority

For Each proc In processes
Console.WriteLine("{0} ({1}), {2}, Priority = {3}", _
proc.ProcessName, _
proc.Id, _
proc.Description, _
proc.Priority)
Next
End Sub

End Class

Public Class ProcessDescription2
Public ProcessName As String
Public Description As String
Public Priority As Integer
End Class

Group Join 會將多個集合合併成單一階層式集合,這與 SQL 中的 LEFT JOIN 類似。
Group Join element [As type] In collection _
On key1 Equals key2 [ And key3 Equals key4 [... ] ] _
Into expressionList
  • element:必要項。代表要聯結之集合的控制項變數。
  • type:選擇項,element 的型別。如果未指定 type,則會從 collection 推斷 element 的型別。
  • collection:必要項。要與 Group Join 運算子左邊的集合進行合併的集合。Group Join 子句可以巢狀於另一個 Join 子句或 Group Join 子句中。
  • key1 Equals key2:必要項。識別要聯結之集合的索引鍵。您必須使用 Equals 運算子來比較要聯結之集合中的索引鍵。您可以使用 And 運算子識別多個索引鍵,藉以合併聯結條件 (Join Condition)。key1 參數必須來自 Join 運算子左邊的集合。key2 參數必須來自 Join 運算子右邊的集合。

    聯結條件中使用的索引鍵,可以是包含集合中之多個項目的運算式。不過,每個索引鍵運算式只能包含其針對之集合中的項目。
  • expressionList:必要項。一個或多個運算式,用於識別如何彙總 (Aggregate) 集合中的項目群組。若要為群組結果指定一個成員名稱,請使用 Group 關鍵字 ( = Group)。您也可以加入要套用至群組的彙總函式 (Aggregate Function)。
Group Join 子句是根據要聯結之集合中的相符索引鍵值來合併兩個集合。所產生的集合包含一個成員,這個成員參考第二個集合中所有與第一個集合中的索引鍵值相符合之項目的集合。您也可以指定彙總函式,以套用至從第二個集合群組得來的項目。
Group Join 作業所產生的集合中,可以包含 From 子句所識別集合中以及 Group Join 子句的Into 子句所識別運算式中的任意值組合。
Group Join 作業會傳回 Group Join 運算子左邊所識別之集合的所有結果。即使要聯結的集合中沒有符合項目,也是一樣。這和 SQL 中的 LEFT OUTER JOIN 相似。
您可以使用 Join 子句,將集合合併成單一集合。這相當於 SQL 中的 INNER JOIN。

下列程式碼範例會使用 Group Join 子句聯結兩個集合:
Dim customerList = From cust In customers _
Group Join ord In orders On _
cust.CustomerID Equals ord.CustomerID _
Into CustomerOrders = Group, _
OrderTotal = Sum(ord.Total) _
Select cust.CompanyName, cust.CustomerID, _
CustomerOrders, OrderTotal

For Each customer In customerList
Console.WriteLine(customer.CompanyName & _
" (" & customer.OrderTotal & ")")

For Each order In customer.CustomerOrders
Console.WriteLine(vbTab & order.OrderID & ": " & order.Total)
Next
Next

六、分組資料(Group By):加入 Group By 子句,根據項目的一個或多個欄位來分組查詢結果中的項目。也可以用來將彙總函式 (Aggregate Function) 套用至每個群組。群組作業是根據一個或多個索引鍵。
Group [ listField1 [, listField2 [...] ] By keyExp1 [, keyExp2 [...] ]
Into aggregateList
  • listField1, listField2:選擇項,明確識別要納入群組結果之欄位的一個或多個查詢變數的欄位。如果未指定欄位,所有查詢變數的欄位都會納入群組結果。
  • keyExp1:必要項。識別用以判斷項目群組之索引鍵的運算式。您可以指定一個以上的索引鍵,藉以指定複合索引鍵。
  • keyExp2:選擇項,與 keyExp1 結合以建立複合索引鍵的一個或多個額外索引鍵。
  • aggregateList:必要項。識別群組彙總方式的一個或多個運算式。若要識別群組結果的成員名稱,請使用下列格式的 Group 關鍵字:
    Into Group
您可以使用 Group By 子句,將查詢結果分成數個群組。群組作業是根據索引鍵,或由多個索引鍵所組成的複合索引鍵。與相符索引鍵值關聯的項目,就會加入相同的群組。

使用 Into 子句的 aggregateList 參數和 Group 關鍵字,可以識別用於參考群組的成員名稱。您也可以將彙總函式加入 Into 子句以計算群組項目的值。
Dim studentsByYear = From student In students _
Select student _
Group By year = student.Year _
Into Classes = Group

For Each yearGroup In studentsByYear
Console.WriteLine(vbCrLf & "Year: " & yearGroup.year)
For Each student In yearGroup.Classes
Console.WriteLine(" " & student.Last & ", " & student.First)
Next
Next

七、彙總函式(Aggregate):將一個或多個彙總函式 (Aggregate Function) 套用至集合。
Aggregate element [As type] In collection _
[, element2 [As type2] In collection2, [...]]
[ clause ]
Into expressionList
  • element:必要項。用來逐一查看集合項目的變數。
  • type:選擇項,element 的型別。如果未指定型別,則會從 collection 推斷 element 的型別。
  • collection:必要項。參考要操作的集合。
  • clause:選擇項,一個或多個查詢子句,例如 Where 子句,以限定套用 Aggregate 子句的查詢結果。
  • expressionList:必要項。一個或多個以逗號分隔的運算式,會識別套用至集合的彙總函式。您可以將別名 (Alias) 套用至彙總函式以指定查詢結果的成員名稱。如果未提供別名,則會使用彙總函式的名稱。如需範例,請參閱本主題稍後關於彙總函式的章節。
Aggregate 子句可以用來將彙總函式包含在查詢中。彙總函式會對值集執行檢查及計算,並傳回單一值。您可以使用查詢結果型別的成員來存取計算值。您可以使用的標準彙總函式為 All, Any、Average、Count、LongCount、Max、Min 及 Sum 函式。

彙總函式的結果包含在查詢結果中,做為查詢結果型別的欄位。您可以套用彙總函式結果的別名,以指定會保留彙總值之查詢結果型別之成員名稱。如果未提供別名,則會使用彙總函式的名稱。

Aggregate 子句可以用來開始查詢,也可以包含在查詢中做為額外子句。如果 Aggregate 子句用來開始查詢,則結果會是單一值,此值是 Into 子句中指定之彙總函式的結果。如果在 Into 子句中指定一個以上的彙總函式,查詢會傳回具有個別屬性的單一型別,以參考 Into 子句中每個彙總函式的結果。如果將 Aggregate 子句做為查詢中的額外子句,則查詢集合中傳回的型別會有個別的屬性,用以參考 Into 子句中每個彙總函式的結果。

All:如果集合中的所有項目都滿足指定的條件則傳回 true,否則會傳回 false。
Dim customerList1 = Aggregate order In orders _
Into AllOrdersOver100 = All(order.Total >= 100)

Any:如果集合中的任何項目滿足指定的條件則傳回 true,否則會傳回 false。
Dim customerList2 = From cust In customers _
Aggregate order In cust.Orders _
Into AnyOrderOver500 = Any(order.Total >= 500)

Average:計算集合中所有項目的平均值,或計算針對集合中所有項目而提供的運算式。
Dim customerOrderAverage = Aggregate order In orders _
Into Average(order.Total)

Count:計算集合中的項目數。您可以提供選擇性的 Boolean 運算式,只計算集合中滿足條件的項目數。
Dim customerOrderAfter1996 = From cust In customers _
Aggregate order In cust.Orders _
Into Count(order.OrderDate > #12/31/1996#)

Group:參考 Group By 或 Group Join 子句之群組結果的查詢結果。Group 函式只有在 Group By 或 Group Join 子句的 Into 子句中才有效。
LongCount:計算集合中的項目數。您可以提供選擇性的 Boolean 運算式,只計算集合中滿足條件的項目數。傳回 Long 的結果。
Max:計算集合的最大值,或計算針對集合中所有項目而提供的運算式。
Dim customerMaxOrder = Aggregate order In orders _
Into MaxOrder = Max(order.Total)

Min:計算集合的最小值,或計算針對集合中所有項目而提供的運算式。
Dim customerMinOrder = From cust In customers _
Aggregate order In cust.Orders _
Into MinOrder = Min(order.Total)

Sum:計算集合中所有項目的總和,或計算針對集合中所有項目而提供的運算式。
Dim customerTotals = From cust In customers _
Aggregate order In cust.Orders _
Into Sum(order.Total)

建立使用者定義的彙總函式: 您可以在查詢運算式中包含自己的自訂彙總函式,方法是將擴充方法加入至 IEnumerable<(Of <(T>)>) 型別。接著,您的自訂方法就可以在參考您的彙總函式的可列舉集合上,執行計算或作業。

例如,下列程式碼範例顯示用於計算數值集合中間值的自訂彙總函式。Median 擴充方法有兩個多載。第一個多載會接受型別 IEnumerable(Of Double) 的集合,做為輸入。如果 Median 彙總函式是針對型別 Double 的查詢欄位進行呼叫,就會呼叫此方法。Median 方法的第二個多載可以傳遞任何泛型型別。Median 方法的泛型多載會採用第二個參數,該參數參考 Func(Of T, Double) Lambda 運算式,將型別的值 (根據集合) 投射為型別 Double 的對應值。接著將中間值的計算委派 (Delegate) 至 Median 方法的其他多載。
Imports System.Runtime.CompilerServices

Module UserDefinedAggregates

' Calculate the median value for a collection of type Double.
_
Function Median(ByVal medianAggregate As IEnumerable(Of Double)) As Double
If medianAggregate.Count = 0 Then
Throw New InvalidOperationException("Cannot compute median for an empty set.")
End If

Dim sortedList = From number In medianAggregate Order By number

Dim medianValue As Double

Dim itemIndex = CInt(Int(sortedList.Count / 2))

If sortedList.Count Mod 2 = 0 Then
' Even number of items in list.
medianValue = ((sortedList(itemIndex) + sortedList(itemIndex - 1)) / 2)
Else
' Odd number of items in list.
medianValue = sortedList(itemIndex)
End If

Return medianValue
End Function

' "Cast" the collection of generic items as type Double and call the
' Median() method to calculate the median value.
_
Function Median(Of T)(ByVal medianAggregate As IEnumerable(Of T), _
ByVal selector As Func(Of T, Double)) As Double
Return (From element In medianAggregate Select selector(element)).Median()
End Function

End Module
下列程式碼範例顯示在型別 Integer 的集合和型別 Double 的集合上,呼叫 Median 彙總函式的範例查詢。在型別 Double 的集合上呼叫 Median 彙總函式的查詢會呼叫 Median 方法的多載,接受型別 Double 的集合以做為輸入。 在型別 Integer 的集合上呼叫 Median 彙總函式的查詢,則會呼叫 Median 方法的泛型多載。
Module Module1
Sub Main()
Dim numbers1 As Integer() = New Integer() {1, 2, 3, 4, 5}
Dim query1 = Aggregate num In numbers1 Into Median(num)
Console.WriteLine("Median = " & query1)
Dim numbers2 As Double() = New Double() {1.9, 2, 8, 4, 5.7, 6, 7.2, 0}
Dim query2 = Aggregate num In numbers2 Into Median()
Console.WriteLine("Median = " & query2)
End Sub
End Module

八、Distinct 子句:限制目前範圍變數的值,以免後續查詢子句中出現重複的值。
Distinct
您可以使用 Distinct 子句傳回只含唯一項目的清單。Distinct 子句會使查詢忽略重複的查詢結果。Distinct 子句會套用至 Select 子句所指定之所有傳回欄位中的重複值。如果未指定 Select 子句,則 Distinct 子句會套用至 From 子句中所識別查詢的範圍變數。如果範圍變數並非不變的型別,則只有當型別的所有成員都符合現有的查詢結果時,查詢才會忽略查詢結果。
Dim customerOrders = From cust In customers, ord In orders _
Where cust.CustomerID = ord.CustomerID _
Select cust.CompanyName, ord.OrderDate _
Distinct

九、Let 子句:計算出一個值並將該值指派給查詢中的新變數。
Let variable = expression [, ...]
  • variable:必要項。可用於參考所提供運算式之結果的別名 (Alias)。
  • expression:必要項。會進行評估並指派給指定變數的運算式。
Let 子句可以讓您計算每個查詢結果的值並使用別名參考這些值。別名可以用在其他子句中,例如 Where 子句。Let 子句可以讓您建立較易讀取的查詢陳述式,因為您可以指定查詢中包含之運算式子句的別名,並且在每次使用運算式子句的時候取代此別名。

您可以在 Let 子句中包含任意數量的 variable 和 expression 指派。請使用逗號 (,) 分隔每個指派。

下列程式碼範例使用 Let 子句計算產品的 10 % 折扣。
Dim discountedProducts = From prod In products _
Let Discount = prod.UnitPrice * 0.1 _
Where Discount >= 50 _
Select prod.ProductName, prod.UnitPrice, Discount

For Each prod In discountedProducts
Console.WriteLine("Product: {0}, Price: {1}, Discounted Price: {2}", _
prod.ProductName, prod.UnitPrice.ToString("$#.00"), _
(prod.UnitPrice - prod.Discount).ToString("$#.00"))
Next

十、Skip 子句:略過集合中指定的項目數目,然後傳回其餘項目。
Skip count
  • count:必要項。數值或運算式,表示要連續略過的項目數。
Skip 子句會使查詢略過結果清單開頭的項目並傳回剩餘項目。略過的項目數是由 count 參數識別。

您可以在查詢的任何區段搭配使用 Skip 子句和 Take 子句,以傳回某個範圍的資料。若要這樣做,請傳遞所需範圍中第一個項目的索引給 Skip 子句,並傳遞範圍的大小給 Take 子句。

當您在查詢中使用 Skip 子句時,可能還需要確保結果的傳回順序可讓 Skip 子句略過所要的結果。

您可以使用 SkipWhile 子句,指定只略過符合所指定條件的特定項目。

下列程式碼範例會搭配使用 Skip 子句和 Take 子句,以頁面為單位傳回查詢資料。GetCustomers 函式會使用 Skip 子句一直略過清單中的客戶直到遇到所提供的起始索引值,然後使用 Take 子句自該索引值起傳回一頁的客戶。
Public Sub PagingSample()
Dim pageNumber As Integer = 0
Dim pageSize As Integer = 10

Dim customersPage = GetCustomers(pageNumber * pageSize, pageSize)

Do While customersPage IsNot Nothing
Console.WriteLine(vbCrLf & "Page: " & pageNumber + 1 & vbCrLf)

For Each cust In customersPage
Console.WriteLine(cust.CustomerID & ", " & cust.CompanyName)
Next

Console.WriteLine(vbCrLf)

pageNumber += 1
customersPage = GetCustomers(pageNumber * pageSize, pageSize)
Loop
End Sub

Public Function GetCustomers(ByVal startIndex As Integer, _
ByVal pageSize As Integer) As List(Of Customer)

Dim customers = GetCustomerList()

Dim returnCustomers = From cust In customers _
Skip startIndex Take pageSize

If returnCustomers.Count = 0 Then Return Nothing

Return returnCustomers
End Function

十一、Skip While 子句:一直略過集合中的項目,直到指定的條件不是 true,然後傳回剩餘項目。
Skip While expression
  • expression:必要項。運算式,表示要對項目測試的條件。這個運算式必須傳回 Boolean 值或功能上的對等用法,例如待評估為 Boolean 的 Integer。
Skip While 子句會自查詢結果開頭起一直略過項目,直到提供的 expression 傳回 false 為止。在 expression 傳回 false 之後,查詢會傳回所有剩餘項目。傳回剩餘結果時會忽略 expression。

Skip While 子句跟Where 子句有個不同點,即 Where 子句可用來排除查詢中所有不符合特定條件的項目。Skip While 子句則只會排除在第一次不符合條件之前遇到的項目。當您使用已排序的查詢結果時,Skip While 子句會很有幫助。

您可以使用 Skip 子句,略過查詢結果的前幾筆結果。

下列程式碼範例會使用 Skip While 子句一直略過結果,直到找到第一個美國客戶為止。
Public Sub SkipWhileSample()
Dim customers = GetCustomerList()

' Return customers starting from the first U.S. customer encountered.
Dim customerList = From cust In customers _
Order By cust.Country _
Skip While IsInternationalCustomer(cust)

For Each cust In customerList
Console.WriteLine(cust.CompanyName & vbTab & cust.Country)
Next
End Sub

Public Function IsInternationalCustomer(ByVal cust As Customer) As Boolean
If cust.Country = "USA" Then Return False

Return True
End Function

十二、Take 子句:自集合的開頭起連續傳回所指定數目的項目。
Take count
  • count:必要項。數值或運算式,表示要連續傳回的項目數。
Take 子句會使查詢自結果清單開頭起,連續加入所指定數目的項目。要加入的項目數是由 count 參數指定。

您可以在查詢的任何區段搭配使用 Take 子句和 Skip 子句,以傳回某個範圍的資料。若要這樣做,請傳遞所需範圍中第一個項目的索引給 Skip 子句,並傳遞範圍的大小給 Take 子句。在此情況下,Take 子句必須指定在 Skip 子句之後。

當您在查詢中使用 Take 子句時,可能還需要確保結果的傳回順序可讓 Take 子句加入所要的結果。

您可以使用 TakeWhile 子句,指定只傳回符合所指定條件的特定項目。

下列程式碼範例會搭配使用 Take 子句和 Skip 子句,以頁面為單位傳回查詢資料。GetCustomers 函式會使用 Skip 子句一直略過清單中的客戶直到遇到所提供的起始索引值,然後使用 Take 子句自該索引值起傳回一頁的客戶。
Public Sub PagingSample()
Dim pageNumber As Integer = 0
Dim pageSize As Integer = 10

Dim customersPage = GetCustomers(pageNumber * pageSize, pageSize)

Do While customersPage IsNot Nothing
Console.WriteLine(vbCrLf & "Page: " & pageNumber + 1 & vbCrLf)

For Each cust In customersPage
Console.WriteLine(cust.CustomerID & ", " & cust.CompanyName)
Next

Console.WriteLine(vbCrLf)

pageNumber += 1
customersPage = GetCustomers(pageNumber * pageSize, pageSize)
Loop
End Sub

Public Function GetCustomers(ByVal startIndex As Integer, _
ByVal pageSize As Integer) As List(Of Customer)

Dim customers = GetCustomerList()

Dim returnCustomers = From cust In customers _
Skip startIndex Take pageSize

If returnCustomers.Count = 0 Then Return Nothing

Return returnCustomers
End Function

十三、Take While 子句:一直包含集合中的項目直到指定的條件不是 true,然後略過剩餘項目。
Take While expression
  • expression:必要項。運算式,表示要對項目測試的條件。這個運算式必須傳回 Boolean 值或功能上的對等用法,例如待評估為 Boolean 的 Integer。
Take While 子句會自查詢結果開頭起一直包含項目,直到提供的 expression 傳回 false 為止。在 expression 傳回 false 之後,查詢會略過所有剩餘項目。傳回剩餘結果時會略過 expression。

Take While 子句跟Where 子句有個不同點,即 Where 子句可用來包含查詢中所有符合特定條件的項目。Take While 子句則只會包含在第一次不合條件之前遇到的項目。當您使用已排序的查詢結果時,Take While 子句會很有幫助。

下列程式碼範例會使用 Take While 子句擷取結果,直到找到第一個沒有任何訂單的客戶為止。
Public Sub TakeWhileSample()
Dim customers = GetCustomerList()

' Return customers until the first customer with no orders is found.
Dim customersWithOrders = From cust In customers _
Order By cust.Orders.Count Descending _
Take While HasOrders(cust)

For Each cust In customersWithOrders
Console.WriteLine(cust.CompanyName & " (" & cust.Orders.Length & ")")
Next
End Sub

Public Function HasOrders(ByVal cust As Customer) As Boolean
If cust.Orders.Length > 0 Then Return True

Return False
End Function