Razorコードの色

Visual Studio のコードの色について。

他と同じように、[ツール(T)]→[オプション(O)] から[環境]→[フォントおよび色] で他と同じように変更できるのですが、「Razor コード」という設定項目があるので、それだろうと思うと、ちょっと残念なことになります。

「Razor コード」だけ設定すると、こんな感じになってしまいます。

中の”ViewData…”という部分が”Razorコード”で、”@Code”, “End Code” の部分は”HTML サーバーサイドスクリプト”だからです。

黄色い部分が”HTMLサーバーサイドスクリプト” にあたります。

なので、

この部分も忘れずに変更する必要があります。

VBで書くラムダ式

LINQはうまく使えば非常に便利なのですが、残念ながらVBで書くと非常にゴチャゴチャします。C# なら => で済む所が、Function やら Sub やら長ったらしく、しかも使い分ける必要があるのが悩みどころです。どういう感じになるか、ひとつやってみます。

お題:小田急線の列車種別・線別の停車駅をクエリして、コンソールに出力します。「正解」はコチラです。

Step1: 駅名を保持するクラスを用意します。列車種別と線名にFlags属性が付いているところに注意してください。

    Private Class Station

        <Flags()>
        Friend Enum TrainKind
            各停 = 1
            区間準急 = 2
            準急 = 4
            多摩急行 = 8
            急行 = 16
            快速急行 = 32
            特急 = 64
        End Enum

        <Flags()>
        Friend Enum Line
            小田原線 = 1
            多摩線 = 2
            江ノ島線 = 4
        End Enum

        Property 駅名 As String
        Property 線 As Line
        Property 停車 As TrainKind

    End Class

Step2:上で作ったクラスに初期値を入れておきます。 Sub main の冒頭でやっておけば十分です。(全駅を書くと大変なので、一部だけにします。)

        Dim colStations As New List(Of Station)
        With colStations
            .Add(New Station With {.駅名 = "代々木上原", .線 = Station.Line.小田原線, .停車 = Station.TrainKind.多摩急行 Or Station.TrainKind.快速急行 Or Station.TrainKind.急行 Or Station.TrainKind.準急 Or Station.TrainKind.区間準急 Or Station.TrainKind.各停})
            .Add(New Station With {.駅名 = "豪徳寺", .線 = Station.Line.小田原線, .停車 = Station.TrainKind.区間準急 Or Station.TrainKind.各停})
            .Add(New Station With {.駅名 = "登戸", .線 = Station.Line.小田原線, .停車 = Station.TrainKind.多摩急行 Or Station.TrainKind.急行 Or Station.TrainKind.準急 Or Station.TrainKind.区間準急 Or Station.TrainKind.各停})
            .Add(New Station With {.駅名 = "向ヶ丘遊園", .線 = Station.Line.小田原線, .停車 = Station.TrainKind.特急 Or Station.TrainKind.急行 Or Station.TrainKind.準急 Or Station.TrainKind.区間準急 Or Station.TrainKind.各停})
            .Add(New Station With {.駅名 = "栗平", .線 = Station.Line.多摩線, .停車 = Station.TrainKind.急行 Or Station.TrainKind.多摩急行 Or Station.TrainKind.区間準急 Or Station.TrainKind.各停})
            .Add(New Station With {.駅名 = "南林間", .線 = Station.Line.江ノ島線, .停車 = Station.TrainKind.急行 Or Station.TrainKind.各停})
        End With

Step3:早速クエリを作ってみます。条件は「小田原線内の多摩急行停車駅」です。まずは、一行で条件を書いてみます。

        Dim queryInLine = colStations.Where(Function(x) (x.停車 And Station.TrainKind.多摩急行) AndAlso (x.線 And Station.Line.小田原線)) _
                            .Select(Function(y) New With {.result = y.駅名 & "[" & y.線.ToString() & "]"})

        For Each stationName In queryInLine
            Console.WriteLine(stationName.result)
        Next

一行で書こうとするとやはりゴチャゴチャします。
このうちwhereの部分だけををC# で書くとすると、

var query = colStations.Where(x => (x.停車.HasFlag(Station.TrainKind.多摩急行)) && (x.線.HasFlag(Station.Line.小田原線)));

と、かなりすっきりするのですが、ないものねだりをしても仕方がありません。

また、Selectで匿名クラスを作っています。匿名クラスのメンバーであろうと、インテリセンスは補完してくれます。

Step4:同じ条件で、複数行で書いてみます。VS2010からは「暗黙の行継続文字」という機能がついたので、狂ったように”_”を付けなくていいところが救いです。「暗黙の行継続文字」が適用される条件については、コチラをご覧下さい。

        Dim queryWithLines = colStations.Where(Function(x)
                                                   Return (x.停車 And Station.TrainKind.多摩急行) _
                                                            AndAlso _
                                                          (x.線 And Station.Line.小田原線)
                                                   End Function
                                ).ToArray()


        Array.ForEach(queryWithLines, Sub(station As Station)
                                      Console.WriteLine(String.Format("{0} [{1}]", station.駅名, station.線))
                                  End Sub)

確かに冗長ですが、見通しはかなり良くなりました。

なお、Array.ForEachの中で直接Console.WriteLineを呼んでで見ましたが、ここは”Sub”であるところに注意してください。つまり、値を返さないので、”Function”ではないのです。この使い分けが若干面倒ではあります。

Step5:最後に、デリゲートを使ってみます。

                Dim fncFilter = Function(x As Station)
                            Return (
                                (x.停車 And Station.TrainKind.多摩急行) _
                                AndAlso _
                                (x.線 And Station.Line.小田原線))
                            End Function

        Dim fncWriteLine = Sub(x As Station)
                               Console.WriteLine(String.Format("{0} [{1}]", x.駅名, x.線))
                           End Sub

        Dim queryUseDeligate = colStations.Where(Function(x) fncFilter(x))
        Array.ForEach(queryUseDeligate.ToArray(), Sub(x As Station) fncWriteLine(x))

C#の「匿名メソッド」のようなものです(コチラによると厳密には違うそうですが)。ここでは細かいことは気にせず、「こういうやり方もありますよ」ということで。
デリゲートの変数名とか書く場所に気をつけてあげれば、見通しの良いコードになりそうな気がします。

文字列の数値変換

受け取った文字列を数値にしなければいけない時、ざっと3通りの方法が用意されています。

  • Integer.Parse(String)
  • Convert.ToInt32(String)
  • CInt(String) または CType(String, typename)  VBのみ

これらがどう違うのか、実験コードを書いてみます。

Sub Main()

    Console.WriteLine("Input number...")
    Dim strOriginal As String = Console.ReadLine()

     Try
        Dim intCastResult As Integer = Integer.Parse(strOriginal)
        Console.WriteLine("int.Parse : {0}", intCastResult)
    Catch ex As Exception
        Console.WriteLine("int.Parse failed.")
    End Try

    Try
        Dim intConvert As Integer = Convert.ToInt32(strOriginal)
        Console.WriteLine("Convert.ToInt32 : {0}", intConvert)
    Catch ex As Exception
        Console.WriteLine("Convert.ToInt32 failed.")
    End Try

    Try
        Dim intCtype As Integer = CType(strOriginal, Integer)
        Console.WriteLine("Ctype : {0}", intCtype)
    Catch ex As Exception
        Console.WriteLine("Ctype failed.")
    End Try

    Console.WriteLine("Hit any key...")
    Console.ReadKey()
End Sub

これを実行してみると、以下のようになります。
“123,456” (カンマ区切りされた数値)
Input number…
123,456
int.Parse failed.
Convert.ToInt32 failed.
Ctype : 123456
Hit any key…

“\123456″ (通貨記号をつけてみた)
Input number…
\123456
int.Parse failed.
Convert.ToInt32 failed.
Ctype : 123456
Hit any key…

“$123456″ (ではドル記号で)
Input number…
$123456
int.Parse failed.
Convert.ToInt32 failed.
Ctype failed.
Hit any key…

“123.456,45” (海外の3桁区切り)
Input number…
123.456,45
int.Parse failed.
Convert.ToInt32 failed.
Ctype failed.
Hit any key…

“&hFE” (では16進で)
Input number…
&hFE
int.Parse failed.
Convert.ToInt32 failed.
Ctype : 254
Hit any key…

CTypeは地域ロケールに依存しつつも、出来る限り変換しようと試みるようです。これが良い場合もあれば悪い場合もあるでしょう。

さらに、もう一歩突っ込んで、Convert.ToInt32 と int.Parse の違いを見てみましょう。
Convert の方は、IFormatProvider を引数に取ることができます。
Parse も IFormatProviderを引数に取ることができますが、NumberStyles列挙体も引数に取ることができます。例えば円記号とカンマ区切りを許容したいのであれば、

Dim intCastResult As Integer = Integer.Parse(strOriginal, Globalization.NumberStyles.AllowThousands Or Globalization.NumberStyles.AllowCurrencySymbol)

と書けることになります。
が、やはりこれも地域ロケールに依存します。
ロケールに依存させたくないというのであれば、最後はIFormatProviderということになるでしょう。

参考:
Int.Parse (MSDN)
Convert.ToInt32 (MSDN)
CType 関数 (MSDN)

Silverlight 上でStringFormat 等のカルチャ指定

例えばこんなの。

<TextBlock x:Name="txtUpdatedDate" HorizontalAlignment="Left" Margin="0,24,0,0" Text="{Binding Mode=OneWay, Path=updatedDate, StringFormat=¥{0:f¥}}" />

コレを出力すると
Suturday, July 09, 2011 3:00 PM
なんて出力されて萎えてしまう訳で。

じゃぁどうするかっていうと、
・コンバーターを自作する
→あるべき姿かも知れないけど、ちょっと大がかりじゃね?

と言う訳で調べてみたら、こんなテがありました。

画面のコンストラクタで

this.Language = XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentCulture.Name);

とする。(要:System.Markup と System.Threading の using指定)

各画面毎にやるとすると面倒くさい気もしますが、まぁこんな手もありますってことで。

Silverlight Tooklit を使って折れ線グラフを出す方法のメモ

Silverlight 4 での開発環境と Tooklit  (2010/4版)の準備は終わっている前提で。

1.表示するデータを用意する。
表示するデータを保持するクラスとそのListを用意。
ここでは、time (x軸), planned (y1軸), result (y2軸) のプロパティを持つクラスと、そのリストを用意。

2. 表示領域を用意する。
Toolkit:Chat を表示領域に貼り付ける。大きさとか色はお好み。

3. グラフのタイトルと軸の作成
グラフタイトルは 貼り付けた Chart の Title プロパティ。
軸は  LinearAxis で、方向は Orientation プロパティで決める。
X軸とY軸なので、LinearAxis は二つは必要と言うことに。
作った LiearAxis を Chart.Axes に Add する。
最大値・最小値の設定が必要なら、 Minimum・Maximum プロパティで設定。

4. 線を用意する
線は LineSeries で。
Title プロパティで凡例に出す文字列を設定。

ItemSource プロパティに先ほどの1.で用意したリストを設定。 ItemSource は IEnumerable を受け取る、
IndependentValueBinding プロパティに、X軸方向に使用する項目の Binding を設定。こんな感じ。

serPlanned.IndependentValueBinding = new Binding("time");

DependentValueBinding も同様に、Y軸方向に使用する項目の Binding を設定。

同じく、作った LineSeries をChart.Series に Add する。

こうすると、取り敢えずグラフは出ます。

注意点としては、自分でグルグルとリストを回して、ポイントを作っていこうとは考えない方が良いと言うこと。Bind して全てを委ねた方がカンタンという話。

SQL Error 16958

 16958 (重大度レベル16)  カーソルが宣言された後に、設定オプションが変更されたので、カーソル操作を完了できませんでした。

いや、カーソル内でそんなことしてないし、何の事だ?と思ったのですが、調べて行き着いたのがコチラ http://social.msdn.microsoft.com/Forums/en-SG/transactsql/thread/c798785f-2bf0-4fe5-b137-e6353f5138ec

呼ばれ先のSPの中で SET でなんかいじってないか?って。QUOTED_IDENTIFIERとか…

で、その問題の子SPを見てみたら、シッカリ一行目にそういうモノがありました。

このメッセージが出た時は、この辺りを疑ってみるのも良いでしょう。

#しかし、相変わらず、SQL Server のエラーメッセージってやつは…

SQL Server のビルド番号

一応Enterprise Manager の右下隅とかに出る訳ですが、製品名とSPです。
まぁ、たいていの場合にはそれで事が足ります。

が、もっと細かい情報が必要になる時とかは、

select @@version

とか

select SERVERPROPERTY(‘productversion’)

とかでビルド番号を調べるとかする訳です。が、ビルド番号が解っても、出てきた結果が結構訳がわからない。9.00.5000 とか、8.00.2282 とかなんじゃそりゃ?という訳で。

そういう時にはコチラ Microsoft SQL Server 2011, 2008R2, 2008, 2005, 2000 and 7.0 Builds( http://sqlserverbuilds.blogspot.com/ ) に一覧表がまとまっています。

SP ばかりではなく、各種パッチ類、CTP 、オマケに製品のコードネームまでつけるイキオイで、ちょいとお役立ち。

VBサンプルコード まとめページ

 まぁVBのサンプルコードの類は、普通にMSDNとか、然るべき定番サイトとか行けば色々とあるのですが。
コチラはMicrosoft VBチーム謹製のサンプルコードまとめ。
リンク先が更にまとめサイトになっていたりもします。

リンク先はコチラ
http://blogs.msdn.com/b/vbteam/archive/2011/01/10/visual-basic-code-examples.aspx

ただ、カテゴリーのアイコンをクリックすると、そのアイコンのページ(つまり画像自体)が表示されるのがなんとも…

SQLiteのテーブル構造を取得するには

データセットとか使ってればそんな必要もないでしょうが、コード内からテーブル構造を取得して云々するコトもあるわけです。

SQL Server なら sp_columns  を呼べばいいわけですが、SQLiteでは?
cmd.exe 呼び出して .schema 叩いて出力をリダイレクトさせて…
なんて力業に出る必要はありませんでした。

System.Data.SQLite にきちんとその道が用意されています。
こんな感じで取得します。

Dim strConnectionString As String = "data source = " & strSQLiteFileName

Using cnSQLite As New SQLiteConnection(strConnectionString)
     cnSQLite.Open()
     '---スキーマ情報を取得する
     Dim objSchemaInfo As DataTable
     Dim strTableInfo() As String = {Nothing, Nothing, "テーブル名", Nothing}
     objSchemaInfo = cnSQLite.GetSchema("Columns", strTableInfo)

     '---取得したスキーマ情報を格納する
     For Each objRow As DataRow In objSchemaInfo.Rows
          Console.Writeline(objRow!COLUMN_NAME.ToString)
     Next

     cnSQLite.Close()
End Using

小さな嵌り所としては、”COLUMN_NAME”を取ってくるのに”!”を使うところ。
“.” ではないところが要注意です。