2014.5.10
今日話す内容は
についてです。
IDEとしての機能や、.NET Frameworkの各名前空間については殆ど触れません
- VisualStudio(VS)と.NETってそもそも何なのか
- VS2003からVS2013までの変更点を時系列順に列挙
- VS2003とVS2013の違いを列挙(↑のまとめ)
- VS2003とVS2013の違いを1項目ずつ解説
- (おまけ)個人的に使いたいOSS
- VS2013の機能をふんだんに使った教材用コードを書きました
- VisualStudio
- 製品としてパッケージ化されたIDE
- .NET Framework
- マイクロソフトが開発したアプリケーションの開発・実行環境
- .NET Framework CLR
- .NET Frameworkの実行ランタイム
- C#/VB
- 主に.NET Frameworkを利用するプログラミング言語
--
図 VSと.NETのバージョン(引用元:++C++; // 未確認飛行C)
--
VSと.NETとC#/VBはそれぞれが密接に関係しあっていますが, 以降の説明では混ぜこぜでお話します. 厳密に知りたい方は随時質問するか,後でググってください.
--
- .NET Framework 2.0
- Generics
- Using
- プロパティのSet/Get個別アクセスタイプ
- Partial Type
- 非同期実装パターン(EAP)
--
- 匿名メソッド
- (VS2010)ラムダ式追加
イテレータ(C#のみ)- (VS2012)VBにもポート
Nullable型(C#のみ)- (VS2008)VBにもポート
--
- .NET Framework 3.0
- LINQ
- ローカル型推論
- 拡張メソッド
- 匿名型
--
- Nullable型
- If式
- Partial Method
- WPF
- WCF
- ASP.NET MVC1
--
- オブジェクト初期化子
ラムダ式(C#のみ)- (VS2010)VBにもポート
コレクション初期化子(C#のみ)- (VS2010)VBにもポート
自動実装プロパティ(C#のみ)- (VS2010)VBにもポート
--
- .NET Framework 4.0
- TDL
- 非同期実装パターン(TAP)
- Rx(ReactiveExtensions)
- 動的言語ランタイム
- ラムダ式
- 自動実装プロパティ
- コレクション初期化子
--
- 暗黙の行連結
呼び出し階層の表示(C#のみ)- (VS2012)VBにもポート
- ASP.NET MVC2
--
- .NET Framework 4.5
- Async-Await
- イテレータ
- 呼び出し階層の表示
- 呼び出し元情報引数
--
- ByVal不要
- NuGet
- ASP.NET MVC3
- Razor
- ASP.NET WebAPI
- SignalR
--
- .NET Framework 4.5.1
- 言語的に大きな変更は無い
- ASP.NET
- ASP.NET MVC4
- (One ASP.NET)
--
図 One ASP.NET BUILD2012
まとめましょう
追加された機能(個人的な重要度順)
* ローカル型推論
+ ByVal不要
* Generics
* Using
* LINQ
+ 匿名メソッド
+ ラムダ式
+ 匿名型
+ オブジェクト初期化子
+ コレクション初期化子
* 拡張メソッド
* 自動実装プロパティ
* 暗黙の行連結
* 非同期実装パターン(TAP)
* Async-Await
* WPF
* Rx(ReactiveExtensions)
* イテレータ
* If式
* Partial Type
* Nullable型
* Partial Method
* 動的言語ランタイム
* 呼び出し階層の表示
* 呼び出し元情報引数
* ASP.NET MVC5
* ASP.NET WebAPI
* ASP.NET SignalR
使われなくなった機能
* 非ジェネリックコレクション
+ ジェネリックコレクションを使う
* 非同期実装パターン(APM・EPM)
+ TAP(Async-Await)を使う
* Threadクラス
+ Taskを使う
Dim num As Integer = 10
- As Integer 書くのが面倒.
- でも遅延バインディングを有効にしてしまうと,型に起因するエラーがランタイムにしかわからない,ボクシングが発生して遅い.
--
Dim num = 10 ' TypeOf num Is Object
Dim str = SubString(num, 10) ' ランタイムエラー(ビルドはできる)
Dim num = 10 ' TypeOf num Is Integer
Dim SubString(num, 10) ' ビルドエラー(ビルド前にもIntellisenseが教えてくれる)
--
- 以下のコードは遅延バインディングではありません
For Each v In Values
Debug.WriteLine(v)
Next
- 当然 v. ←この時点でインテリセンスが効きます
- デフォルトで引数ByValで渡されるのでわざわざ書かなくていい.地味にありがたい
- 後に出てくる匿名関数・ラムダ式がとっても便利に使える
- .
ByRefは書いてね
- C++のテンプレート/Javaのジェネリック
- ジェネリックについての説明は必要ないと思うので省いていい?
- 例えばどういう時に使う?
- Integer型のみのコレクションが欲しい
- String型のみのコレクションも欲しい
- オレオレクラスのコレクションが欲しい
- どんな型でも引数に取れるメソッドが欲しい
--
Class IntArray
Private array As New ArrayList
Public Sub Add(ByVal data As Integer)
array.Add(data)
End Sub
End Class
Class StringArray
Private array As New ArrayList
Public Sub Add(ByVal data As String)
array.Add(data)
End Sub
End Class
クラス間の差は型だけしかない⇒DRYじゃない.
--
' クラスを一つ作るだけでいい
Class TypeArray(Of T)
Private array As New ArrayList
Public Sub Add(ByVal data As T)
array.Add(data)
End Sub
End Class
' 使い方
Sub Method()
Dim intArray As New TypeArray(Of Integer)
Dim strArray As New TypeArray(Of String)
intArray.Add(10) ' OK
intArray.Add("10") ' BuildError
End Sub
--
実は.NET Frameworkも2.0からジェネリック対応になっているので,型指定コレクションは標準で用意されています.
Sub Method()
'コレだけで超多機能な型指定コレクションが使えます
Dim intList As New List(Of Integer)
intList.Add(10)
intList.Count()
intList.Sort()
End Sub
--
余談
VB.NET 2003 で List(Of String)と同等のコレクションクラス (String型のみを格納する標準的な機能(Count, IndexOf, Insert, Remove等)を持つコレクションクラス) を作るには?
' IListを継承する
Class MyCollection
Implements IList
--
Class MyCollection
Implements IList
Public Sub CopyTo(ByVal array As System.Array, ByVal index As Integer) Implements System.Collections.ICollection.CopyTo
End Sub
Public ReadOnly Property Count() As Integer Implements System.Collections.ICollection.Count
Get
End Get
End Property
Public ReadOnly Property IsSynchronized() As Boolean Implements System.Collections.ICollection.IsSynchronized
Get
End Get
End Property
Public ReadOnly Property SyncRoot() As Object Implements System.Collections.ICollection.SyncRoot
Get
End Get
End Property
Public Function GetEnumerator() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
End Function
Public Function Add(ByVal value As Object) As Integer Implements System.Collections.IList.Add
End Function
Public Sub Clear() Implements System.Collections.IList.Clear
End Sub
Public Function Contains(ByVal value As Object) As Boolean Implements System.Collections.IList.Contains
End Function
Public Function IndexOf(ByVal value As Object) As Integer Implements System.Collections.IList.IndexOf
End Function
Public Sub Insert(ByVal index As Integer, ByVal value As Object) Implements System.Collections.IList.Insert
End Sub
Public ReadOnly Property IsFixedSize() As Boolean Implements System.Collections.IList.IsFixedSize
Get
End Get
End Property
Public ReadOnly Property IsReadOnly() As Boolean Implements System.Collections.IList.IsReadOnly
Get
End Get
End Property
Default Public Property Item(ByVal index As Integer) As Object Implements System.Collections.IList.Item
Get
End Get
Set(ByVal Value As Object)
End Set
End Property
Public Sub Remove(ByVal value As Object) Implements System.Collections.IList.Remove
End Sub
Public Sub RemoveAt(ByVal index As Integer) Implements System.Collections.IList.RemoveAt
End Sub
End Class
'とっても面倒くさい
--
- IListを実装せずにオレオレコレクションクラスで良いのでは?
- みんな大好きForEach文が使えない
- Sortができない
- Filterができない
- ⇒使いづらい⇒使われない
--
余談2
-
For Eachが使える場面でまさかForなんて使ってませんよね?
-
For Each文を使うには?
-
⇒IEnumerableを実装すれば使えます(VS2005のVBではクッソ面倒くさいけど)
-
※ VisualStudio2012のVBからは,イテレータ(Yield)を使うことでIEnumerableの実装がクッソ簡単になっています.上記は忘れてください.数行で書けるようになります.
Class MyCollection
Implements IEnumerable
Private _array As New ArrayList
Public Sub Add(ByVal o As Object)
_array.Add(o)
End Sub
Public Function GetEnumerator() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
Return New MyCollectionEnumerator(_array)
End Function
Private Class MyCollectionEnumerator
Implements IEnumerator
Private _index As Integer = -1
Private ReadOnly _array As ArrayList
Public Sub New(ByVal array As ArrayList)
_array = array
End Sub
Public ReadOnly Property Current() As Object Implements System.Collections.IEnumerator.Current
Get
Return _array(_index)
End Get
End Property
Public Function MoveNext() As Boolean Implements System.Collections.IEnumerator.MoveNext
_index += 1
Return _index <> _array.Count
End Function
Public Sub Reset() Implements System.Collections.IEnumerator.Reset
_index = -1
End Sub
End Class
End Class
IDbDataReader(OracleDataReaderとかの抽象クラス)を使い終わったらDispose()を必ず呼びたい
--
Dim rdr As OracleDataReader
Try
dllxv.XVFOPNRDR(rdr, sql)
' do something
Finally
rdr.Dispose()
End Try
- 忘れがち.
- リソースリークは気づきにくい(でも少しずつ被害が・・・)
- Try~Finallyは例外を記述するための構文なのにリソース管理に用いるのは普通じゃない(けど慣例化している)
Using rdr
' do something
End Using 'ここでrdr.Dispose()が例外の有無に関係なく必ず呼ばれる
…の前に,以下の5つの説明を先にします.
- 匿名メソッド
- ラムダ式
- オブジェクト初期化子
- 匿名型
- コレクション初期化子
- 使い捨ての関数
- 関数オブジェクトをメソッド内で直ぐに作れる.
- いろんな場面で重宝するが,若干コードが読みづらくなる.C#のラムダ式が欲しくなる.(VS2010でVBでも使えるようになった!)
- VB.NET 2008のLINQでよく使う.ただし,VB.NET 2010以降はラムダ式の方を主に使うので使用頻度は低い.
--
Delegate Sub Action()
Sub WriteHoge()
Debug.WriteLine("Hoge")
End Sub
Sub Main()
Dim act As New Action(AddressOf WriteHoge)
act()
End Sub
Sub Main()
Dim act = _
Sub()
Debug.WriteLine("Hoge")
End Sub
act()
End Sub
匿名関数のシンタックスシュガー
'ラムダ式
Dim plus = Function(x) x + 1
'匿名関数
Dim plus = Function(x)
Return x + 1
End Function
※余談 C#のラムダ式
var plus = x => x + 1
構造体やクラスのアクセス可能フィールド/プロパティの初期化がとっても楽になる.
Structure A
Public x As Integer
Public y As Integer
End Structure
Dim a As A
a.x = 10
a.y = 20
Dim a As New A With {.x = 10, .y = 20}
--
- 最も有効な場面
- →インスタンスを宣言せずに,生成してすぐ使う
Dim patients = GetPatients(New SearchOption With {
.TestPatient = True,
.Gender = Male,
.Nyuuin = True
})
SearchOptionインスタンスが宣言されないのでグローバルスコープが汚れない
事前にクラスを定義せずに,オブジェクト初期化子が使える
Dim a As New With {.X = 10, .Y = 20}
Console.WriteLine(a.X) 'a. の時点でインテリセンスが働く
- 例えば,メソッドの戻り値や引数で,いくつかの変数をまとめて渡したい時に使う.
- 後述のLINQで多用する.
- 遅延バインディングでは無い
HogeMethod(strPatno, New {.Name="白十字花子", .Birthday="19500101" } )
配列以外のコレクションもワンライナーで初期化できる
Dim nums As New ArrayList
nums.Add(1)
nums.Add(2)
nums.Add(3)
Dim nums As New List(Of Integer) From {1, 2, 3}
- Language INtegrated Query
- VisualStudio 2008 の最大の変更点.(LINQ前,LINQ後と呼ばれることもあるらしい)
--
'準備---------------------
Class Hoge
Public Id As Integer
Public Name As String
End Class
Dim hogeCollection As New ArrayList
hogeCollection.Add(New Hoge(0, "花子"))
hogeCollection.Add(New Hoge(1, "太郎"))
hogeCollection.Add(New Hoge(2, "次郎"))
'クエリ構文-------------------
Dim q = From h In hogeCollection
Where h.name.Contains("郎")
Select h.name
For Each e In q
Debug.WriteLine(e)
End For
' デバッグ出力------
' 太郎
' 次郎
'メソッド構文(VB.NET 2010)---------
Dim q2 = hogeCollection
.Where( Function (x) x.name.Contains("郎") )
.Select(Function (x) x.name )
For Each e In q2
Debug.WriteLine(e)
End For
' 太郎
' 次郎
' ラムダ式・匿名関数を使わない場合のメソッド構文
q = hogeCollection
.Where(dlgtContains("郎"))
.Select(dlgtGetName)
--
Dim linq = hoge.
Where(Function(x) x.kbn = 10).
Where(Function(x) x.ymd <= 20130828).
Select(Function(x) x.name.Trim)
- DataViewと違って,インテリセンスが完全に効く
- DataViewよりパフォーマンスがいい(Boxingが発生しない,式の評価が遅延される)
- DataViewよりも多機能(Count, Sum, Aggregate, SelectMany, Join, Uniqueなど)
--
- IEnumerable(Of T)を実装する全てのコレクション処理で使える.使うべき.
- 例えば,VB.NET 2003 で良くある処理
dtv.RowFilter = "ORD_INF_KBN = '20' "
For Each row As DataRowView In dtv
Debug.WriteLine(CStr(row("PATNO")))
Next
このコードの潜在的な危険性
- dtvに ORD_INF_KBN 列は存在するか?
- ORD_INF_KBN 列は String型 なのか?
- dtvに PATNO 列は存在するか?
- CStr(row("PATNO"))で正しくキャストできるか?
たった4行で4つもランタイムにしかわからないバグの可能性が潜んでいるし,コードを書く際,dtvに何の列が存在するのか覚えていないとコードが書けない,読めない.
--
linq.Where(Function(x) x.Kbn = '20')
.WriteLine(Function(x) x.Patno )
Class Hoge
Public Kbn As String
Public Patno As String
End Class
--
- dtvに ORD_INF_KBN 列は存在するか?
- 存在するプロパティ(Public Kbn As String)以外を指定するとビルドエラー
- インテリセンスが利くのでコード書く時点で候補が提示される
- ORD_INF_KBN 列は String型 なのか?
- KbnプロパティはString型.考える必要なし
- dtvに PATNO 列は存在するか?
- 存在するプロパティのみ指定可能.考える必要なし
- CStr(row("PATNO"))で正しくキャストできるか?
- PatnoプロパティはString型なのでキャスト不要.
- 型からはわからない情報(Nothingかどうか)等は従来通り考慮する必要あり
--
- クラスのメソッドを,クラスの外に書ける.
- というより,第1引数の型のメソッドを書ける
- 既存のコードを変更することができないクラス・インターフェイスを拡張できる
- 例えば,DataTable.ToCsv()とか作ればデバッグが楽になる
- C1FlexGrid.ToString()を作ってデバッグ出力してみたりとか
Dim tbl As DataTable
' tbl.ToCsv() というメソッド呼び出しをしたい!
<Extension()>
Public Function ToCsv(t As DataTable) As String
' ここでCSV出力する
End Function
tbl.ToCsv() ' ビルドOK
- Set/Getを持つプロパティをワンライナーで記述できる.
- パブリックフィールドは全てプロパティにすべき
- シグニチャを変えずに後から実装を変更できる
--
Class C
Private _str As String
Public Property Str() As String
Get
Return _str
End Get
Set(ByVal Value)
_str = Value
End Set
End Property
End Class
Class C
Public Property Str As String
End Class
--
でも実際良く使うのはこんなやつですよね…(自動実装プロパティ使えない)
Class C
Private _str As String
Public Property Str() As String
Get
Return _str
End Get
Private Set(ByVal Value)
_str = Value
End Set
End Property
' または
Public ReadOnly Property Str2() As String
Get
Return _str
End Get
End Property
End Class
引数リストが長いとき,複数行に分けて書きたい
Public Sub Hoge(ByVal a As Integer, ByVal b As Integer, ByVal c As Integer)
↓
' VB.NET 2003
Public Sub Hoge(ByVal a As Integer, _
ByVal b As Integer, _
ByVal c As Integer)
' VB.NET 2010
Public Sub Hoge(ByVal a As Integer,
ByVal b As Integer,
ByVal c As Integer)
- ほかにも,いろんな場所で暗黙の行連結が有効になっているので,今まで "_" を書いていた部分が省略できるかも
- .NET Framework4.0からTaskクラスが追加され,TAP(Task-based Asynchronous Pattern)が主流に.
- 現在の非同期処理もTAPが主流です.APM,EAPは駆逐されました.完全に忘れていいです.
Task.Factory.StartNew(New Addressof SetButtonEnableFalse)
.ContinueWith(New Addressof Sleep30Sec)
.ContinueWith(New Addressof SetButtonEnableTrue,
TaskScheduler.FromCurrentSynchronizationContext())
--
余談
--
AEP(Asynchronous Programming Model)
Dim asyncHoge = New dlgtAsync(AddressOf subAsyncHoge)
Dim req = WebRequest.Create("http://hoge")
req.BeginGetResponse(asyncHoge, req)
Delegate Function dlgtAsync(ByVal ar As IAsyncResult)
Sub subAsyncHoge(ByVal ar As AsyncResult)
Dim res = (ar.AsyncState).EndGetResponse(ar)
End Sub
--
EAP(Event-based Asynchronous Pattern)
Dim c As New WebClient
c.Encoding = Encoding.UTF8
AddHandler c.DownloadStringCompleted, AddressOf subWriteString
c.DownloadStringAsync(New Uri("http://hoge"))
Sub subWriteString(ByVal sender As Object, ByVal args As DownloadStringCompletedEventArgs)
Dim result = args.Result
Console.WriteLine(result)
End Sub
- LINQと同じ位の衝撃
- 非同期プログラムが革新的に簡単に書ける(同期的にかける).
- Reactive Extensionsと比べても楽
Async Sub btnOK_Click(sender As Object, e As RoutedEventArgs)
Me.btnOK.IsEnabled = False
Await Task.Run(New AddressOf DoSomething)
Me.btnOK.IsEnabled = True
End Sub
- Windows.Formsに代わる,UIとロジックを分離して記述できるGUIフレームワーク.
- MVVMアーキテクチャ
- XamlでUIを記述する
- マルチ解像度に対応できる
- Windows.Formsとは異なるパラダイムで設計されているので習得にはかなーり時間かかりそう
- Expression Blend という,UIデザインのみを作りこめるツールも標準である
- この頃からLINQを非同期に記述できる,**Rx(Reactive Extensions)**が流行しだした.
- .NET Frameworkには含まれていないが,Microsoftの正規プロダクト
- 現在でももちろん使われている素晴らしい技術
- ただし,今ならTAPのAsync-Awaitである程度代用できる
--
例えばこういうことができます.
'ボタンのClickイベントがRaiseされたら
'ボタンをEnable=Falseにする
'その後別スレッドの監視を開始し
'何かしら時間のかかる作業を行う
'最初のスレッドの監視を再開し
'ボタンを有効にする
Observable
.FromEventPattern(Me.btnOK, "Click")
.Do(SetEnableFalse)
.ObserveOn(Scheduler.ThreadPool)
.Do(DoSomething)
.ObserveOn(SynchronizationContext.Current)
.Subscribe(SetEnableTrue)
- IEnumerable(Of T)の実装が驚くほど簡単になる.
- つまりForEach対応のコレクションクラスが簡単に作れる.
- ForEachが使えるということはLINQも使える.
- C#が2005で導入した機能がようやくVBにポーティングされた.
- LINQと合わさって最強に見える.
- コレクションクラス作るのが面倒だからDataTableにデータ突っ込んでDataViewでゴチャゴチャやる.ということが減らせる.
Class HogeCollection
Implements IEnumerable(Of Hoge)
Dim _list As New List(Of Hoge)
Iterator Function GetEnumerator() As IEnumerator(Of Hoge)
For Each h In _list
Yield h ' For文でまわしてYield呼ぶだけ!
Next
End Function
End Class
--
再掲 Yieldを使わない場合(VB.NET 2003)
Class MyCollection
Implements IEnumerable
Private _array As New ArrayList
Public Sub Add(ByVal o As Object)
_array.Add(o)
End Sub
Public Function GetEnumerator() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
Return New MyCollectionEnumerator(_array)
End Function
Private Class MyCollectionEnumerator
Implements IEnumerator
Private _index As Integer = -1
Private ReadOnly _array As ArrayList
Public Sub New(ByVal array As ArrayList)
_array = array
End Sub
Public ReadOnly Property Current() As Object Implements System.Collections.IEnumerator.Current
Get
Return _array(_index)
End Get
End Property
Public Function MoveNext() As Boolean Implements System.Collections.IEnumerator.MoveNext
_index += 1
Return _index <> _array.Count
End Function
Public Sub Reset() Implements System.Collections.IEnumerator.Reset
_index = -1
End Sub
End Class
End Class
- 所謂3項演算子.
- VB.NET2003の不十分な3項演算子(IIfメソッド)を強化したもの
- 戻り値 = If(条件, 真の場合, 偽の場合)
' VB.NET 2003
hoge = IIf(IsDBNull(hoge), "", CStr(hoge))
' hogeがDBNullかどうかに関わらず真と偽の両方の引数が評価される.
' 例えば上の例では,hogeがDBNullの場合にCStr(hoge)が評価されて落ちる.
' VB.NET 2008
hoge = If(IsDBNull(hoge), "", CStr(hoge))
' hogeがDBNullなら""しか評価されない```
---
## VS2003 To VS2013 簡易まとめ
* ジェネリックの使い方に慣れてください.
* ラムダ式の使い方に慣れてください.
* リソース管理はUsingを使ってください.
* 型推論は強力なので頼ってください.
* 型推論は**遅延バインディングではありません**
* LINQはとっても便利なので使い方に慣れてください.
* オブジェクト初期化子,コレクション初期化子も便利です.
* 複数行にまたがるコードでも "_" が不要になる場合が多くあります.
* 非同期処理はTAP(Async/Await)を真っ先に検討してください.
---
# おまけ
OSSの紹介
* Dapper
+ とっても便利なMicroORM
* ReactiveExtensions
+ 非同期LINQ
---
以上。
---
### 言語機能の学習には以下のサイトが非常に有効です.
* C#によるプログラミング入門 | ++C++;// 未確認飛行 C
+ http://ufcpp.net/study/csharp/
* .NET Framework | ++C++;// 未確認飛行 C
+ http://ufcpp.net/study/dotnet/index.html
---
C#のサイトですが,現在C#の機能の8割はVBにポートされているので気にせず読みましょう.