しらいしさん…

linuxに1000回くらい殺されてるしとりまmicrosoft様をageてくわ

時代の変遷から見るラムダ式の使い方

なんだよラムダ式って…ってなったしぱっっと見どう考えても意味が分からないけど、C#の「なるべく文章量は少なくかつ反射的に読めるようにする」の正統進化ポケモンみたいな感じなんだな

全体的に何

「メソッドを引数として渡したい」場合。返り値のあるメソッドであればそんなことは考えなくていいけど、voidなどで行う分岐・抽出系の処理でしばしばそういうことがある。普通にメソッド呼び出しすればいいんじゃない…?って話だけど、引数として使えるので、もう入力時の便利さが違う。毎回()を入力しなくていい。

サンプルコード

「5, 3, 9, 6, 7, 5, 8, 1, 0, 5, 10, 4」の中から、偶数のみを抽出(手法:n % 2 == 0)する。

偶数判定をするjudgeメソッドを、引数としてCountメソッドで利用したい。

デリゲート式

public delegate bool Judgement(int value);

public int Count(int numbers, Judgement judge)
{
int count = 0;
foreach (var n in numbers)
{
if (judge(n) == true)
{
count++;
}
}
return count;
}

public void Do()
{
var numbers = new { 5, 3, 9, 6, 7, 5, 8, 1, 0, 5, 10, 4 };
//judgementの中身の処理としてIsEvenを代入
Judgement judge = IsEven;
var count = Count(numbers, judge);
Console.WriteLine(count);

}

public bool IsEven(int n)
{
return n % 2 == 0;
}

 public delegate 返り値 メソッド名(引数)」がほぼ魔法の呪文。

型はメソッド名の変数が宣言できて、その中身としたいメソッドを変数形式で直接代入できる。

Judgement judge = IsEven;

 で引数にしたいデリゲート「Judgement」に中身を代入して、

var count = Count(numbers, judge);

 で中身を持ったJudgementを引数として指定することができる。

 

ただしこれ、わざわざIsEvenメソッドスコープを作成して中身をコーディングしちゃってるので、労力がそんなに削減できてない。

 

匿名メソッド

private int Count(int numbers, Predicate<int> judge)
{
int count = 0;
foreach (var n in numbers)
{
if (judge(n) == true)
{
count++;
}
}
return count;
}

public void Do()
{
var numbers = new { 5, 3, 9, 6, 7, 5, 8, 1, 0, 5, 10, 4 };
var count = Count(numbers, delegate (int n) { return n % 2 == 0; });
Console.WriteLine(count);
}

 メソッドスコープ作成はやめよう、という感じでこうなった。分量は確かに減った気がする。

 

ラムダ式

private int Count(int numbers, Predicate<int> judge)
{
int count = 0;
foreach (var n in numbers)
{
if (judge(n) == true)
{
count++;
}
}
return count;
}

public void Do()
{
var numbers = new { 5, 3, 9, 6, 7, 5, 8, 1, 0, 5, 10, 4 };
var count = Count(numbers, n => n % 2 == 0);
Console.WriteLine(count);
}

 所要分量10文字以内の限界に挑戦、成功。

 public delegate 返り値 メソッド名(引数)」はやっぱり魔法の呪文。(ただし、deligateでない場合もある)

var count = Count(numbers, n => n % 2 == 0); 

 「n(とりあえず任意の変数) => 処理文」が定型文。なんだこのn…って感じで初見はビビリが走るけど、ただのメソッドの引数。

基本的には勝手に型推論をしてくれるので、型宣言も必要ない。*1

処理に対して引数が複数ある場合は、引数部分を()で囲む。「(n,s) =>」って感じ。引数がない場合、「() =>」みたいな書き方もできるけど、フレームワークが限定されるしあんまり今回の趣旨にも合わないし覚えにくいし読みにくいしなので推奨しない。普通にメソッドを使おう。

 

 

ラムダ式の有効活用

単純に処理を表記する他にも色々お手軽な使い方があって、たとえば

var country = new List<string>{"Tokyo", "New Delhi", "Bangkok", "London", "Paris", "Berlin", "Canberra", "Hong Kong"};

って感じのリストがあるとして、以下の使い方ができる。

List<T>クラスのメソッドを利用する

//文字「A」がリストに含まれるかどうかを判定する*2

ver exists = country.Exists(s => s[0] =='A');

Console.WriteLine(exists)

これの問題は、手軽だけどほぼList<T>でしか利用できないという点。他の配列系要素でいろいろしたい場合は、ちょっと手間と分量がかかるけどIEnumarable<T>(ほぼすべての配列要素系に適用できる)下のLINQを使う。

LINQのwhere句、select句(クエリ演算子)の具体的な条件・処理として利用する

where句は、その名の通り要素抽出の条件にするクエリ演算子。単純に要素の抽出で済ませたいのであれば、ここに書くだけでよい。

//5文字以下の国名のみ抽出する。*3

IEnumerable<string> query = country.Where(s => s.Length <= 5);

select句は、引数として渡ってきた要素に対し、ラムダ式で指定した変換処理をするクエリ演算子。もちろん単体で使う事もできるし、where句とかの後ろ(改行はしたほうがよさそう)に.で続けてwhere句で抽出した要素に対して処理を行う使い方が割と基本な気がする。*4

//5文字以下の国名のみ抽出して、抽出したものを全て小文字に変換する*5

IEnumerable<string> query = country.Where(s => s.Length <= 5)

                                               .Select(s => s.ToLower());

その他にも、クエリ演算子は山ほどあったりするので、後々調べよう(本の説明がよくわからなかったので若干詰み感がある)

forEachの短縮

戻り値の型はdeligate<T>ではなく、Action<T>。『T型の引数を一つとり返値が無い関数』、ほぼvoidってこと。分量が増えるくらいならこれにしてもいい気がする。ただし、間に何らかの処理を入れる場合、普通にforEachにしたほうが分かりやすいか?と思う。

//listの内容を全て表示する

country.forEach(s => Console.WriteLine(s));

 

けっこう頑張って書いたね。LINQはこれ単体で書籍が出るほどの沼らしいので、まあ、やっていきましょうって感じ。やっていきましょう

*1:ただし間違われたり難しかったりする場合もあるにはあるので、複数だったり複雑な処理の場合は「int n」というように型宣言しておくとよい

*2:大文字のAが含まれる国名は一件もないので、この場合falseがWriteLineされる

*3:Tokyo、Parisが抽出される。

*4:こうして.でクエリ演算子やメソッドを結合することを「メソッドチェーン」というらしいよ。なんか調べるとメソッドチェーン大好きマンがいっぱいいるわ。怖いわ

*5:tokyo、parisが抽出される。

フォーカス遷移時のイベント処理の使い道【Enter、Leave】

コントロールが遷移する時のイベント、本当はバリデーションとかでもっと種類があるけど、プレーンで一番使うのはこの2つではないかな?という気がする。バリデーション系の奴は後々まとめよう。

Leaveイベント

あるコントロールからフォーカスが外れた際に、そのコントロールまたは他のコントロールに対して何らかの処理をしたいとき。そのテキストボックスに入力された数値や文字列の内容を判定して、デフォルト値に変換したり、整数を小数値に置き換えたりする。バリデーションでエラーを出すほどではないような奴。

private void textBox1_Leave(object sender,
 System.EventArgs e)
{
//空欄だった場合にデフォルト値を入力する if(string.isNullorEmpty(textBox1.text))
{
textBox1.text = 0; } }

ただし、ここらへんの処理は、ValidatingイベントとValidatedの合わせ技でも実現可能で、考え次第。エラーを出す必要はないかっていう時にはLeaveでよかろうと思う。

Enterイベント

あるコントロールフォーカスが移ってきた瞬間そのコントロールに対して何らかの処理をしたいとき。前のテキストボックスで入力した内容に応じて自分の内容や属性を変更したりできる。理論上他のコントロールに対して処理もできるとは思うけど、それはLeaveでできるので、このイベントではあくまで自コントロールに限定するのがベストな気がする。

private void textBox2_Enter(object sender,
 System.EventArgs e)
{
//前の項目が空欄だったら現項目の背景色を赤に
if (string.isNullorEmpty(textBox1.text))
{
textBox2.BackColor = Color.Red;
}
 //現項目に記入があれば背景色を緑に
else if(!string.isNullorEmpty(textBox1.text))
 {
textBox2.BackColor = Color.Green;
}
}

 

GotFocusとLostFocus

正直ほとんど上の二種と同じだしMSDNさんが「この二種は低水準なイベントメソッドなので、LeaveとEnterを使うべきです」と仰っているので、使わないに越したことはない。

むしろ、使っているのを見たら何かがやべー現場なのでやべーと思ったほうがいい。そういう闇の気配ガンガンにしてる。

構文スコープで外部変数に代入したい

変数nを用意して、分岐・ループの中でnに違う値を代入して、入った値をスコープ終了後に反映させるようにしたい。
ただ、ここで

switch文なら

var n;

switch(x)
{
 case 1:
 n = 1;
 break;    

 case 2:
 n = 2;
 break;    
}

if文なら

var n;

if(x == 1)
{
 n = 1;
}
else
{
 n = 2;
}

for文なら

var n;
             
for (int i = 0; i < 100; i++)
{
 n = i;
}

という風に初期値を入れずに書いてしまうと、ブロックのどこかを必ず通るようになっていても「未割り当てのローカル変数が使用されました。」のコンパイルエラーになる。
C#の「null参照の危険性がありますよ」的なことを警告してくれる親切心で、対処はブロック侵入前にnに値を代入しておくこと。

var n = null;

if(x == 1)
{
 n = 1;
}
else
{
 n = 2;
}

switch文ならスコープ内にdefaultを入れることでも解決できる

var n;

switch(x)
{
 case 1:
 n = 1;
 break;    

 case 2:
 n = 2;
 break; 

 default:
 n = 0;
 break;  
}

「未割り当てのローカル変数が使用されました。」はよく出るけど、「値が代入されるように記述されていない」か、この構文スコープの問題で発生してることが多いから、慌てずデバッグするんだぞ。

こまめなインデントでストレスを下げる

基本的にVisualStudioは自動的に整形してくれるけど、キャレットやカーソルを戻して入力とかすると自動機能が解除されちゃって、自分でやってみたいな空気になったりする。

そんなときはインデント整形のショートカットキーを使おうね。

 

①一部分だけ選択して

Ctrl + k の後 Ctrl + f

②ファイル全体にかけたい場合

Ctrl + k の後 Ctrl + d

 

ファイルがよほど巨大でなければ、見落としもあるのでファイル全体にかければいいね。俺のせいじゃねえ。俺のせいじゃねえ。

keyPressとkeyDownとkeyUpイベントって結局何が違うんだ

正直な話VisualStudio上のイベントプロパティの説明文が畜生すぎる

発生タイミング

1.keyDown

2.keyPress

3.KeyUp

ここまではまあわかるね。単語的にね。えらい。ただ、そもそもkeyDownとkeyPressは機能が異なるので、発生タイミングはそれほど意味を持たないかもしれない。

発生条件と返却・処理値

keyPress
  • 文字キーを押された時のみ発生する
  • 主にChar(keyChar)を処理・返却する
  • 入力された「文字」の判定をする際に使う
  • 下図の範囲

f:id:HSShiraisi:20170626100204j:plain

keyDown、keyUp
  • 修飾キーを含めた全てのキーが押された時に発生する
  • キーコード(e.KeyCode、Keys)とかキーの機能オブジェクト(enumだったりboolだったり)や関数(ProcessTabKey)とかを処理・返却する
  • 修飾キー(方向キーとかEnterとかTabとか)が入力されたことを検知する時に使う事が多い 
  • 下図の範囲

f:id:HSShiraisi:20170626102746j:plain

keyUp・keyDownだとこことか

C# のキーイベントであるKeyDownイベントとKeyUpイベントの基本的な使用例 - Yahoo!知恵袋

C# にて、Shiftキー、又は、 Controlキー、又は、 Altキーを押しながら、文字キー等を押した場合のKeyDownイベントとKeyUpイベントの使用例 - Yahoo!知恵袋

って知恵ノート終わるんかいお前…

後でこっそりコピーしておきたいけどこの作者のノート量勉強にはなるけどえげつないから全部は確保しきれないよ…クソーッ

linuxをTeratermから使いたい①【プレーンテキスト認証】

つまりSSH接続がしたいわけ。

①プレーンテキスト認証方式

②公開鍵認証方式

があって、公開鍵認証方式のほうがセキュリティとしては固いらしいぞ。

いつ何時ヤバイ何かが現れるか知れないので、どっちも知っておくことにしよう…とりあえず簡単らしいプレーンテキストから…(弱気

参照

実践初級ITブログ Ubuntuにteratermからsshプレインテキスト方式でログインする

VirtualBox + UbuntuでNAT接続のポートフォワーディングを行う方法 - 大人になったら肺呼吸

今回virtualboxだからやらないけど、多分普通にやるならこれを軸に設定するのかなと思う(脳死してるので読んでない)

SSHポートフォワード(トンネリング)を使って、遠隔地からLAN内のコンピュータにログインする - ククログ(2014-09-12)

内容まとめ

linux
  1. 対象の仮想マシンの[設定]→[ネットワーク]→[割り当て]を「NAT」に
  2. 同タブ内の[高度]にチェックすると詳細設定がニュッと出るので出てきたボタン[ポートフォワーディング]を押す(他の項目は無編集でよい)
  3. 出てくるダイアログに行を追加。「名前:任意のなにか / プロトコルTCP / ホストポート:普通なら22 / ゲストポート:普通なら22」を入力する。このとき、「ホストIP」「ゲストIP」は入力しない
  4. ifconfigコマンドでipアドレスを確認しておく。
Teraterm
  1. [TCP/IP]にチェック
  2. [ホスト]に上記4で確認したipアドレスを入力
  3. [サービス]はSSHにし、OKボタンを押下
  4. [ユーザ名]と[パスフレーズ]にホスト側のユーザ名をパスワードを入力
  5. [プレインパスワードを使う]にチェックし、OKを押下

できたけどなにかがおかしい

ループバックアドレスでしかログインできてないやん

ipアドレスでやらないと共有ログインとかできひんやろが

NICの設定がちゃんとできてないのかenp0s3になったことで何かが起きているのかえー…なんだ…なんなんだ…一体どこからなんだ…

TextBoxに数字しか入力できないようにしたい

タイトル通りの事をふんわりとやりたいと考えて、

参照

以下がヒットしました。 TextBoxに数字しか入力できないようにする: .NET Tips: C#, VB.NET

やるべきこと

各コントロールのKeyPressイベントに

 //数字以外(スペース含む)のとき
 if (!Char.IsDigit(e.KeyChar) && e.KeyChar != '\b')
  {
    //イベントを強制終了
    e.handled = true
  }

を入れる。
※必要なコントロール一個一個に対し同じ処理をするので、共通部品メソッドとして別だししたほうがよい

脳死しかける

Q.「tryParse使えばいいんじゃ?
A.「使えませんtryParseはstringにしか使えないしkeyPressのKeyEventArgsがstringを扱うことはほぼ確実にないからです」

入力内容が文字列として判定可能なのはコントロールのtext値として設定された後なんだね。
あと、e.handledもkey系のイベントでしか使えないぞ。

tryPerseが使えるパターン

目的を具体化して、

記入に誤りがあった場合、
1. 入力確定ボタンを押した際にtryPerseしてエラーを出す
2. フォーカスを変えた際にtryPerseしてエラーを出すorデフォルト値を入れる
であればある程度活用のめどがありそう。
ただし、1はボタンメソッドに複数コントロールのtextを全部持ってくる必要がありそうなのと、2はストレスフルだったり入力者側のミスが出そうでしんどそう。しんどそう…