原文刊於 .NET Magazine國際中文電子雜誌
此篇文章改寫原刊於 .NET Magazine的文章,原文是使用Visual Studio 11 Developer Preview版工具撰寫的,本文改用Visual Studio Beta工具測試,重新抓圖並修訂部分工具的差異。原文URL:
本文撰寫時使用的工具是Visual Studio 11 Beta,資料庫則為SQL Server 2012 Express版,因此本文探討的內容在正式版上市時可能不適用。
Visual Studio 11 Beta開發工具
Visual Studio 2010與Visual Studio 11 Beta開發工具兩者可以並存在相同的電腦環境上。更好的是,專案檔案與方案檔案具備向下相容的能力。不過,參考圖1所示,目前在筆者的電腦中安裝了.NET Framework 4版,從Visual Studio 11 Beta專案的「Target Framework」設定來看,目前Visual Studio 11 Beta不僅能夠開發預設的.NET Framework 4.5版程式,也能夠開發前版.NET Framework2~.NET Framework 4的應用程式。
圖 1:Visual Studio 11 Beta專案的「Target Framework」設定。
當你在Visual Studio 11 Beta開啟使用Visual Studio 2010設計的方案或專案時,會有提示訊息跳出來,例如底下開啟一個使用Visual Studio 2010撰寫,「Target Framework」為.NET Framework 3.5的專案會出現以下訊息:
圖 2:升級提示訊息。
你可以手動將應用程式升級到4.5版,只要設定專案屬性頁的Target Framework為適當版本即可:
圖 3:設定Target Framework。
此時會顯示提示訊息:
圖 4:升級提示訊息。
當然,被Visual Studio 11 Beta開啟並升級成.NET Framework 4.5的專案,後續無法再利用Visual Studio 2010開啟繼續進行設計的動作。但若是在Visual Studio 11 Beta中將專案的目標Framework設定為.NET Framework 4,則使用Visual Studio 2010還是可以開啟此專案。
「Solution Explorer」視窗
「Solution Explorer」視窗可以用來檢視類別的成員、進行成員搜尋動作,或者開啟兩個以上的「Solution Explorer」視窗,便於在多個螢幕中顯示。
在「Solution Explorer」視窗中,你可以檢視專案中某項目包含的內容,例如,參考圖5所示,MainWindow.xaml.cs檔案中,MainWindow類別包含了MainWindow方法以及其它成員,您也可以檢視其基礎型別(Base Types)、衍生型別(Derived Types),或被哪些項目使用(Is Used By)。
圖 5:檢視項目包含的內容。
你也可以使用Contains功能來檢視類別中包含哪些成員,例如在MainWindow的父類別Window項目上,按滑鼠右鍵,選取「Contains」:
圖 6:Contains。
將列出Window類別所有成員:
圖 7:列出Window類別所有成員。
「Solution Explorer」視窗上方的向左、向右鍵頭可以回到上一個、或下一個檢視畫面。
此外「Solution Explorer」視窗也提供了簡易的搜尋功能,便於找尋專案中的程式碼,底下的圖8顯示輸入「Initial」關鍵字之後,表列出符合查詢條件的結果。
圖 8:「Solution Explorer」視窗的搜尋功能。
另外您也可以利用「Solution Explorer」視窗來檢視方法的呼叫歷程,類似前版Visual Studio 2010 C#專案中的「Call Hierarchy」視窗的功能,參考圖9所示。
圖 9:檢視方法的呼叫歷程。
當設計工具中開啟的檔案很多時,有時很難尋找,你可以利用將常用檔案釘選(Pin)起來,以便於找尋,參考圖10所示:
圖 10:檔案釘選功能。
檔案預覽功能(File preview)
Visual Studio 11 Beta新增一個檔案預覽(File preview)功能,可以將未開啟在設計畫面中的檔案自動開啟提供預覽的動作。預設在Visual Studio 11 Beta 的「Tools」->「Options」->「Environment」->「Tabs and Windows」頁面中,已勾選「Allow new files to be opened in the preview tab」項目,和「Single – click opens files in the preview tab」-「Solution Explorer ( Alt + Click to avoid previewing)」以及「Find Results」項目,參考圖11所示。
圖 11:啟用檔案預覽(File preview)功能。
舉例來說,參考圖12,當應用程式執行,進入中斷模式來除錯時,您可以直接點選程式碼視窗中的Employee類別上,按下滑鼠右鍵,從突顯示選單,選取「Go To Definition」項目,Visual Studio 11 Beta會自動地開啟Employee類別定義所在的檔案,表列在編輯視窗的右上方。
圖 12:檔案預覽。
你可以點選預覽視窗上的「Open」按鈕,它就會變成是一般的分頁,參考圖13所示。
圖 13:檔案預覽Open功能。
若是使用Visual Studio 11 Beta的功能搜尋程式碼,搜尋的結果會表列在「Find Results」視窗。現在「Find Results」視窗也提供檔案預覽的功能。例如底下範例搜尋應用程式中的Employee類別,當你點選「Find Results」視窗搜尋到的第一個項目時,預覽檔案的分頁也會自動顯示,參考圖14所示。
圖 14:「Find Results」視窗檔案預覽的功能。
「Quick Launch」視窗
當Visual Studio開發工具的功能愈來愈複雜時,想要尋找選單中的選項就是一件相當困難的事。還好,在Visual Studio 11 Beta工具的右上角有一個新的「Quick Launch」視窗,可以快速地找到Visual Studio 11 Beta的選單選項,參考圖15所示,你可以按下「CTRL+Q」來操作它。
圖 15:「Quick Launch」視窗。
例如想要變更程式碼的字型,可以在「Quick Launch」視窗輸入「fonts」字串,按下鍵盤的「Enter」鍵,Visual Studio 11 Beta便會自動表列出和Fonts相關的設定步驟,顯示在下方。當你點選列在下方的「Environment -> Fonts and Colors」選項時,Visual Studio 11 Beta也會自動顯示「Options」對話盒,並停留在「Fonts and Colors」設定畫面,您便可以馬上更改相關的設定,非常的便利,參考圖16所示。
圖 16:「Quick Launch」視窗。
「Quick Launch」視窗也可以應用在搜尋已開啟的文件,例如圖17顯示,若想要快速地切換到已開啟的MainWindow.xaml檔案,只要輸入關鍵字,如「MainWi」就行了:
圖 17:在「Quick Launch」視窗搜尋已開啟的文件。
增強的搜尋功能
隨著.NET Framework版本的更新,可以使用在應用程式介面的控制項以及專案檔案也愈來愈多,不方便找尋。現在「Toolbox」、「Solution Explorer」與「Error List」…等多個視窗都具備搜尋的功能,方便尋找控制項、檔案或錯誤資訊等等。
要使用「Toolbox」搜尋的功能,您可以利用上方的「Search Toolbox」文字方塊輸入關鍵字來篩選控制項,或是直接將游標停留在工具箱上後,直接輸入關鍵字。例如以下輸入「ca」字串,Visual Studio 11 Beta工具箱的游標會自動停留在Calendar控制項上,按下鍵盤的Tab鍵可以切換到下一個符合搜尋關鍵字的控制項上,若要取消查詢動作,可以按下鍵盤的ESC鍵,參考圖18所示。
圖 18:搜尋控制項。
使用規則運算式搜尋
「Quick Find」、「Quick Replace」、「Find in Files」與「Replace in Files」視窗可以用來搜尋、取代專案或檔案中的內容。現在搜尋時又新增一個選項,可以使用規則運算式定義篩選條件來進行搜尋。
參考底下的「Quick Find」視窗,您可以按下「CTRL + F」來開啟這個視窗,它會出現在程式編輯視窗的右上角。搜尋時只要輸入有意義的規則運算式,並勾選「Use Regular Expression」選項即可,搜尋到的內容會以黃色標示。若要檢視下一個符合篩選條件的內容,可以按下「Quick Find」視窗右上方的向右、向左箭頭,或按下鍵盤F3 (Find Next) 或SHIFT + F3 (Find Previous) ,參考圖19所示:
圖 19:使用規則運算式搜尋。
Visual Basic與C#新功能-Async
Visual Basic與C#新增一個非同步功能(Async),讓非同步應用程式的開發能夠更簡單。
Visual Basic與C#都新增兩個運算子,Async (適用於Visual Basic),async(適用於C#)以及 Await (適用於Visual Basic),await(適用於C#)。 在定義方法時,方法的前方可以加上Async(async)關鍵字,以通知編譯程式某個方法或某一個Lambda運算式是非同步的,這個標識async關鍵字的方法稱為-非同步方法(async method)
非同步方法(async method)宣告時,要加上async關鍵字。
await運算子則是套用在一項非同步方法的作業(Task)上,停滯此方法程式的執行,直到作業執行完畢為止,才將執行權交還給呼叫的方法。作業(Task)就是你欲以非同步方式執行的動作。不過,await運算子只能夠在有標示async關鍵字的非同步方法中使用。
底下的程式碼片斷中的AsyncMethod方法就是一個非同步方法,方法中await關鍵字套用在叫用Task.Delay方法這一行程式,讓程式暫停一秒執行,然後再回傳「Hello」字串:
C#語法:
{
await Task.Delay( 1000 );
return "Hello" ;
}
Visual Basic語法:
Await Task.Delay( 1000 )
Return "Hello"
End Function
await運算式並不會停滯目前正在執行中的執行緒,而是告知編譯器將非同步方法剩餘未執行的程式碼標示為一項await 工作,控制權會交還呼叫非同步方法的呼叫者。當非同步作業執行完畢時,就會執行非同步方法剩餘未執行的程式碼。
再者,以C#程式語言來說,非同步方法的回傳值只能夠是void、Task或Task<T>型別,T代表回傳值的型別。若以Visual Basic程式語言來說,非同步方法可以是一個sub,或function,但function的回傳值只能夠是Task或Task(of T)型別。此例中AsyncMethod非同步方法回傳的是一個Task<string>(C#),Task(Of String) (Visual Basic),這個方法回傳值的型別是string型別。在命名時按慣例,會以「Async」字串結尾。
C#語法:
{
Task< string > myTask = (Task< string >) AsyncMethod();
string result = await myTask;
Console.WriteLine( result );
}
Visual Basic語法:
Dim myTask As Task( Of String ) = AsyncMethod()
Dim result As String = Await myTask
Console.WriteLine( result )
End Sub
底下的主控台範例程式展示了非同步與同步的程式寫法,C#語法:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace CSNew
{
class Class1
{
static void Main(string[] args)
{
Console.WriteLine( "Sync demo started.." );
GetNameSync( );
Console.WriteLine( "Main finished" );
Console.ReadLine( );
Console.WriteLine( "Async demo started.." );
GetNameAsync ();
Console.WriteLine( "Main finished" );
Console.ReadLine();
}
public static async Task< string > AsyncMethod()
{
await Task.Delay( 1000 );
return "Hello";
}
public static async Task< string > SynchMethod()
{
Thread.Sleep( 1000 );
return "Hello";
}
private static async void GetNameSync()
{
Task< string > myTask = (Task< string >) SynchMethod();
string result = await myTask;
Console.WriteLine( result );
}
private static async void GetNameAsync()
{
Task< string > myTask = (Task< string >) AsyncMethod();
string result = await myTask;
Console.WriteLine( result );
}
}
}
非同步方法中若沒有使用await關鍵字,編譯程式時,Visual Studio 11 Beta會顯示警告訊息,但不代表錯誤,程式可以照常執行,不過,會被視為同步的方法來執行,例如範例中的SynchMethod方法。此程式執行的結果參考如下,參考圖20所示:
圖 20:async範例。
若改用Visual Basic程式語言, Async範例如下:
Imports System.Threading
Module Module1
Sub Main()
Console.WriteLine( "Sync demo started.." )
GetNameSync( )
Console.WriteLine( "Main finished" )
Console.ReadLine( )
Console.WriteLine( "Async demo started.." )
GetNameAsync( )
Console.WriteLine( "Main finished" )
Console.ReadLine( )
End Sub
Private Async Sub GetNameSync()
Dim myTask As Task( Of String ) = SynchMethod()
Dim result As String = Await myTask
Console.WriteLine( result )
End Sub
Private Async Sub GetNameAsync()
Dim myTask As Task( Of String ) = AsyncMethod()
Dim result As String = Await myTask
Console.WriteLine( result )
End Sub
Public Async Function AsyncMethod() As Task( Of String )
Await Task.Delay( 1000 )
Return "Hello"
End Function
Public Async Function SynchMethod() As Task( Of String )
Thread.Sleep( 1000 )
Return "Hello"
End Function
End Module
再者,async關鍵字可以套用在方法或Lambda運算式上,例如以下範例所示,C#語法:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace CSNew
{
class Class1
{
static void Main ( string [ ] args )
{
Console.WriteLine("Async demo started..");
GetNameAsync();
Console.WriteLine("Main finished");
Console.ReadLine();
}
private static async void GetNameAsync ( )
{
Func<Task> labexp = async ( ) =>
{
await Task.Delay(1000);
Console.WriteLine("Hello");
};
await Run(labexp);
}
public static Task Run ( Func<Task> t )
{
if ( t != null )
return Task.Run(t);
return null;
}
}
}
Visual Basic語法:
Imports System.Threading
Module Module1
Sub Main( )
Console.WriteLine( "Async demo started.." )
GetNameAsync( )
Console.WriteLine( "Main finished" )
Console.ReadLine( )
End Sub
Private Async Sub GetNameAsync( )
Dim labexp As Func( Of Task ) = Async Function( )
Await Task.Delay( 1000 )
Console.WriteLine( "Hello" )
End Function
Await Run( labexp )
End Sub
Public Function Run( t As Func( Of Task ) )
If ( t <> Nothing ) Then
Return Task.Run( t )
End If
Return Nothing
End Function
End Module
Task類別定義在System.Threading.Tasks命名空間下,代表一個非同步的作業,範例中叫用Run方法來執行Func<Task >,它可以用來呼叫一個沒有參數、會回傳一個Task型別的方法。
Visual Basic新語法-Iterator
Iterator通常都是應用在巡覽集合或陣列中的項目,C#在2005年Visual Studio 2005的版本中就已經支援,而Visual Basic直到Visual Studio 11 Beta 版才新增了Iterator語法 - Yield。
我們先參考一個簡單的iterator範例,定義一個列舉方法 (Iterator method) - GetName,此方法定義時,前方標示了Iterator Modifer,方法中利用Yield關鍵字,依序回傳「Mary」、「Candy」、「Lily」以及「Sandy」等字串。Main方法中利用For Each..Next方法列舉GetName方法回傳的結果。
Sub Main( )
For Each n As String In GetName( )
Console.Write( n & "," )
Next
End Sub
Public Iterator Function GetName( ) As System.Collections.IEnumerable
Yield "Mary"
Yield "Candy"
Yield "Lily"
Yield "Sandy"
End Function
End Module
支援泛型型別
列舉方法 (Iterator method)的回傳型別也可以是一個泛型型別,例如底下範例,GetName方法回傳的是System.Collections.Generic.IEnumerable(Of String)型別。
Sub Main( )
For Each n As String In GetName( )
Console.Write( n & "," )
Next
End Sub
Public Iterator Function GetName( ) As System.Collections.Generic.IEnumerable( Of String )
Yield "Mary"
Yield "Candy"
Yield "Lily"
Yield "Sandy"
End Function
End Module
支援屬性語法
Iterator Modifer除了可以應用在Function之外,也可以應用在屬性的語法上。例如以下範例Module1中GetNames屬性內宣告一個做為iterator的Get存取子(Get Accessor)。Main方法中則利用for each迴圈列出屬性中的所有字串。
Module Module1
Sub Main( )
For Each n As String In Module1.GetNames( )
Console.Write( n & "," )
Next
End Sub
Public ReadOnly Iterator Property GetNames( ) As IEnumerable( Of String )
Get
Yield "Mary"
Yield "Candy"
Yield "Lily"
Yield "Sandy"
End Get
End Property
End Module
自訂類別
自訂的類別若需要實作列舉功能,可以實作IEnumerable介面,它包含一個GetEnumerator方法,只要實作這個方法就可以了。例如以下範例,EmployeeNameList類別實作IEnumerable介面,EmployeeNameList類別的建構函式建立了代表名稱的字串加入nameList集合中,GetEnumerator方法則透過for each搭配yield語法,一次傳回集合中的一個字串:
Module Module1
Sub Main( )
Dim empList As New EmployeeNameList ()
For Each n As String In empList
Console.Write( n & "," )
Next
End Sub
End Module
Public Class EmployeeNameList
Implements IEnumerable
Dim nameList As New List( Of String )
Sub New()
nameList.Add( "Mary" )
nameList.Add( "Candy" )
nameList.Add( "Lily" )
nameList.Add( "Sandy" )
End Sub
Public Iterator Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
For Each n In nameList
Yield n
Next
End Function
End Class
匿名方法
Visual Basic中的匿名方法也可以是一個列舉方法,例如以下定義的匿名方法前方加註了Iterator關鍵字,方法中使用Yield一次回傳一個字串[P1] :
Dim nameList = Iterator Function( ) As IEnumerable( Of String )
Yield "Mary"
Yield "Candy"
Yield "Lily"
Yield "Sandy"
End Function
For Each n As String In nameList.Invoke( )
Console.Write( n & "," )
Next
呼叫階層(Call Hierarchy)
Visual Basic新增了呼叫階層(Call Hierarchy)視窗,這個功能在前一版Visual Studio 2010的C#開發工具中便已提供。由於Visual Studio 11 Beta 的方案總管(Solution Explorer)視窗也有類似「呼叫階層」視窗的功能,因此這項新功能似乎不太令人驚豔了,參考圖21所示。
圖 21:Visual Basic 的「Call Hierarchy」視窗。
Global關鍵字
Global關鍵字可以讓你存取到.NET的System命名空間,在你自訂命名空間和System下命名空間名稱相衝突時非常的有用。例如以下範例,自訂的A命名空間下包含一個子System命名空間。此命名空間和.NET Framework的System命名空間名稱相同,造成衝突。
Namespace System
Class Test
Sub Print( )
System.Console.WriteLine( "Hello" )
End Sub
End Class
End Namespace
End Namespace
因此,當你在Test類別中,撰寫System.Console.WriteLine這行程式碼時,Visual Studio便會出現錯誤訊息,無法識別System下的Console類別,參考圖22所示:
圖 22:Global關鍵字可以解決名稱衝突。
我們可以將程式碼變更為改用Global關鍵字存取到.NET Framework中的System命名空間來解決這個命名空間衝突的問題:
Namespace System
Class Test
Sub Print( )
Global.System.Console.WriteLine( "Hello" )
End Sub
End Class
End Namespace
End Namespace
沒有留言:
張貼留言