プロになるためのWeb技術入門

JavaでのWEBアプリを作成するに当たって読みました。
JSP,サーブレットといった技術はまさに理解したかった項目だったので良かったです。
過去、ネットワーク越しに文書を共有したいというニーズがあってHTTPが生まれた。

クライアントの操作によって対象を動作させたいというニーズがあってCGIが生まれた

CGIを高速に大量に動作させる為にServletが生まれた

Servletのモジュールをクライアント側とサーバ側で分離させる為にJSPが生まれた
という様に時系列に沿って各技術を説明してくれています。
結果、アプリケーションサーバ(Tomcat)、JSP、サーブレット
に多くのページを割いていますが、非Javaエンジニアに取っては分かり難くないでしょうか?
大丈夫でしょうか? PHPやRubyエンジニアに取ってもこれらは有用でしょうか?
.Net限定エンジニアに取っては難しいと思います。
ただここを理解すればIISの設定等も格段にやりやすくなるとは思いますが。
WEBの技術がPerl→Javaを経て現在に至る事の証左とも言えるでしょう。

他、以下について説明しています。
サーバ, クライアントモデル
HTTPプロトコル
IPアドレス
URL, URI
GET, POST
CGI
Cookie
Session
Web システム構成
WEB サーバ
DB サーバ
アプリケーションサーバ
Webアプリーション
フレームワーク
Web アーキテクチャ
MVC Pattern
layer Pattern

本サイトの参照記事
[JAVA]

プログラム言語 エンコード・デコード処理

エンコードとは

符号化
文字に対してコンピュータで扱う文字コード=コード(数値)を割り振る事
テキストエディタで文字データを作成・保存した際、
OS毎の割り振られる文字コードは以下の通り。
・Windows:Shift_JIS
・UNIX系:EUC
・Mac:Unicode
テキストエディタの機能によって保存時の文字コードを変更する事は可能
OSに関わらずUTF-8が国際的に標準化されつつある。
特にHTML5では推奨される。
漢字をUTF-8で保存すると容量が増えるという問題点あり
XMLでは、XML宣言でエンコードの種類を明示的に表記する
<?xml version="1.0" encoding="Shift_JIS"?>
<a>~</a>

割り振られた文字コードを解析して読み込む事をデコードと言う。
割り振られた文字コードと違う文字コードで読み込んだ場合、文字化けする。

読込

string[] s;
s = File.ReadAllLines(@"D:\~txt", Encoding.Default);
s = File.ReadAllLines(@"D:\~.txt", Encoding.GetEncoding(name: "Shift_JIS"));
s = File.ReadAllLines(@"D:\~.txt", Encoding.Unicode);
s = File.ReadAllLines(@"D:\~.txt", Encoding.UTF8);

書込

File.WriteAllLines(@"D:\~txt", @"内容", Encoding.Default);
File.WriteAllLines(@"D:\~.txt", @"内容", Encoding.GetEncoding(name: "Shift_JIS"));
File.WriteAllLines(@"D:\~.txt", @"内容", Encoding.Unicode);
File.WriteAllLines(@"D:\~.txt", @"内容", Encoding.UTF8);

BASE64エンコード・デコード

BASE64とは?
バイナリデータ→テキストデータ
への変換方式
英数字のみで構成される
暗号ではない

import java.io.IOException;
import org.apache.commons.codec.binary.Base64;

public class base64test {
 public static void main(String[] args) {
  try{
   String after = encodeBase64("~");
  }
  catch ( ~ ){
   ~
  }

 }
 
 public static String encodeBase64(String before) throws IOException {
  byte[] out = Base64.encodeBase64(before.getBytes());
  return new String(out, "shift_jis");
 }
}

Sub main
 after = encode("~")
 after = decode("~")
End Sub

'Base64文字列にエンコードする
Public Function encode(val As String) As String

 Dim objBase64 As Object
 Dim b() As Byte
 b = stringToByte(val)
 
 'Msxml2.DOMDocumentオブジェクト = XML操作オブジェクト
 Set objBase64 = CreateObject("MSXML2.DOMDocument").createElement("b64")
 objBase64.DataType = "bin.base64"
 objBase64.nodeTypedValue = b
 encode = objBase64.text
 
 Set objBase64 = Nothing

End Function

'Base64文字列をデコードする
Public Function decode(val As String) As String
 Dim objBase64 As Object
 'Msxml2.DOMDocumentオブジェクト = XML操作オブジェクト
 Set objBase64 = CreateObject("MSXML2.DOMDocument").createElement("b64")
 objBase64.DataType = "bin.base64"
 objBase64.text = val
 
 Dim b() As Byte
 b = objBase64.nodeTypedValue
 decode = byteToString(b)
 
 Set objBase64 = Nothing

End Function

'文字列バイト列に変換する
Public Function stringToByte(ByVal strData As String) As Byte()

 Dim objStream As Object
 Set objStream = CreateObject("ADODB.Stream")
 
 objStream.Open
 objStream.Type = adTypeText
 objStream.Charset = "utf-8"
 objStream.WriteText strData
 
 objStream.Position = 0
 objStream.Type = adTypeBinary
 objStream.Position = 3
 stringToByte = objStream.Read
 
 objStream.Close
 Set objStream = Nothing
 
End Function

プログラム言語 XML操作

作成

文字列指定

using System.Xml;

const string url = "http://example.com/";
var doc = new XmlDocument();

親要素・属性
var root = doc.CreateElement("root", url);
var att = doc.CreateAttribute("att");
att.AppendChild(doc.CreateTextNode("sample"));
root.Attributes.Append(att);

子要素
var child1 = doc.CreateElement("child1", url);
child1.AppendChild(doc.CreateTextNode("sample1"));
root.AppendChild(child1);

var child2 = doc.CreateElement("child2", url);
child2.AppendChild(doc.CreateTextNode("sample2"));
root.AppendChild(child2);

doc.AppendChild(root);

Console.WriteLine(doc.OuterXml());

親要素・属性・子要素をまとめて構築
doc.LoadXml("<root att='sample' xmlns='http://example.com/'><child1>sample</child1><child2>sample</child2></root>");

Console.WriteLine(doc.OuterXml());

結果
<root att="sample" xmlns="http://example.com/">
 <child1>sample</child1>
 <child2>sample</child2>
</root>

using System.Xml.Linq;

var doc = new XDocument();
XNamespace name = "http://example.com/";
var root = new XElement(name + "root");
var attRoot = new XAttribute("attRoot", "value");
var elm1 = new XElement(name: "elm1", content: "value1");
var elm2 = new XElement(name: "elm2", content: "value2");
var attElm = new XAttribute("attElm", "value");

root.Add(elm1);
root.Add(elm2);
elm2.Add(attElm);
root.Add(attRoot);
doc.Add(root);

Console.WriteLine(doc.ToString());

XNamespace name = "http://example.com/";
var root = new XElement(
 name + "root", new XAttribute("att", "valueAtt"),
 new XElement("elm1", "value1"),
 new XElement("elm2", new XAttribute("attElm", "value"), "value2"));

Console.WriteLine(root.ToString());

結果
<root attRoot="value" xmlns="http://example.com/" >
 <elm1>value</elm1>
 <elm2 attElm="value">value</elm2>
</root>

文字列→XML変換

var doc = XDocument.Parse("<root xmlns='https://office-yone.com/'><a>システム開発</a><b>ホームページ作成</b></root>");

結果
Console.WriteLine(doc.ToString());
<root xmlns='https://office-yone.com/'>
 <a>システム開発</a>
 <b>ホームページ作成</b>
</root>

読取

値で検索

var doc = XDocument.Parse("<root xmlns='https://office-yone.com/'><a>システム開発</a><b type="web">ホームページ作成</b><c><d>インフラ構築</d></c></root>");

XNamespace name = "https://office-yone.com/";
int count = doc.Descendants(name + "a").Count();
count:1

int count = doc.Descendants(name + "b").Where( x => x.Value == "ホームページ作成").Count();
count:1

int count = doc.Descendants(name + "b").Where( x => x.Attribute("type").Value == "web").Count();


<root xmlns='https://office-yone.com/'>
 <a>システム開発</a>
 <b type="web">ホームページ作成</b>
 <c>
  <d>インフラ構築</d>
 </c>
</root>

要素名で検索

var doc = XDocument.Parse("<a><b><c>WordPress</c></b></a>");
string val = doc.Element("a").Element("b").Element("c").Value;
val:WordPress

<a>
 <b>
  <c>WordPress</c>
 </b>
</a>

var doc = XDocument.Parse("<a><b><c>C#</c></b><b><c>Java</c></b></a>");
foreach (var elm in doc.Element("a").Elements("b").Elements("c"))
{
 Console.WriteLine(elm.Value);
};
→C# Java

<a>
 <b>
  <c>C#</c>
 </b>
 <b>
  <c>Java</c>
 </b>
</a>

プログラム言語 属性

概要

クラスやメンバーの付加情報
デバック中に機能するもの、コンパイル中に機能するもの、実行中に機能するものと様々。
クラス利用者へのメッセージ・指示、コンパイラへの指示等。

エントリポイント

///

/// アプリケーションのメイン エントリ ポイントです。
///

[STAThread]
static void Main()
{
Application.Run(new Form1());
}

スレッド種類

[STAThread]
メソッドがシングルスレッドアパートメントである事を明示
元々WindowsのCOMコンポーネントは、STA(SingleThreadApartment)でないとエラーになる為、
Mainメソッドにはこの属性が付与されている。

別スレッドにてActiveXコントロールを使用する際には以下の設定が必要。
Thread other = new Thread(start: new ThreadStart(非同期処理));
other.SetApartmentState(ApartmentState.STA);
other.Start();

コーディング時の警告

[Obsolete("警告:代わりに~を使って下さい。")]
public static void OldMethod(){}

[Obsolete("エラー:代わりに~を使って下さい。", true)]
public static void VeryOldMethod(){}

public static void Main()
{
  // コンパイル時:警告。「警告:代わりに~を使って下さい。」
  OldMethod();
  
  // コンパイル時:エラー。「エラー:代わりに~を使って下さい」
  VeryOldMethod();
}

プログラム言語 非同期処理

用語解説

非同期処理

複数の別の処理を同時に行う。
マルチコア環境(複数のCPUで処理する)の場合、高速化する可能性あり。

並列(並行)処理

単一の処理を複数に分割して行う。

プロセス

プログラムの実行単位
プロセスは1つ以上のスレッド、固有のヒープメモリ領域等で構成される。
起動や切り替えに時間が掛かる。
複数プロセスに対する処理時間の割り当てはOSが行う。
具体的にはプロセス内のスレッドに対して処理を割り当てる。

スレッド

CPUの利用単位
スレッド単位でスタック、CPUレジスタのコピーを持つ
ヒープメモリ領域は同一プロセス内のスレッドで共用する
起動や切り替えが速い。
複数スレッドに対する処理時間の割り当てはOSが行う。

UIスレッド
=メインスレッド
※エンド・ユーザーからの入力を受け付けたり、UIを描画したりするスレッド
ワーカースレッド
UIスレッドのバックグラウンドで動作する別スレッド

非同期処理(マルチスレッド)のメリット

プロセスA
 スレッド1
 スレッド2
プロセスB
 スレッド1
だとプロセスAの方が多くの処理時間が割り当てられる。
よってマルチスレッド処理は有用。

同期制御

複数のスレッドがタイミングを計りながらリソースに対してアクセスする事。

プリエンプティブ

マルチタスク、マルチスレッドの処理におけるスケジューリング方法の1つ。
タスク(スレッド)が動作中であろうが一定時間が経過すると強制的に処理を別タスクへ移す。

強調的(ノン・プリエンプティブ)

各タスクが自己申告で都合の良い場所まで処理を終えてから処理を別タスクへ移す。
実際にはシステムコールを呼び出すタイミングで処理が移される。
多段フィードバックキュー
・短いタスクを優先する
・FIFO(FirstInFirstOut)方式で最初にスケジューリングされたタスクを優先する
等の優先順位の重みに違いがあるプリエンプティブ方式

スレッドセーフ

1つのデータ(オブジェクト)に対して、複数のスレッドが同時にアクセスした場合、データの不整合が発生する。
排他制御を施し、この現象が発生しないクラスのこと。
スレッドセーフなクラスは継承禁止にすべき。
排他制御処理は時間が掛かる為、無用な使用は控えるべき。

スタック

FIFO方式で使用するメモリ領域。
スタックポインタ(SP)レジスタにスタックのアドレスを保持する事で、
スタックの読み込み先、書き込み先を判定する。
ローカル変数、関数の戻り先等に使用。

マルチスレッドにおけるスタック利用

スレッドを別に作成する毎にスタック領域が確保される(デフォルト:1MB)。
スレッドの切り替え時にはCPUレジスタの内容を退避/復帰する必要がある為、退避用メモリ領域も必要(デフォルト:1MB)。
容量及び、確保に時間を要するのでマルチスレッドはコストが高いと言われる。

スレッドプール

スレッド用のプログラムを保持しておくメモリ領域。
マルチスレッド用のスタック領域を破棄せずに使いまわす事で容量及び処理時間を短縮する目的で使用される。
.NET4.0以前
ThreadPool.QueueUserWorkItemメソッドを利用
(省略)
.NET4.0以降
=Taskクラスを利用したスレッド

実例

別スレッド呼び出し(引数無し)

以下の内容は現在ではメリット無し
非同期処理はスレッドプール(Taskクラス)を使う。

static void Main(string[] args)
{
  ThreadStartデリゲートにメソッドを指定
  Thread other1 = new Thread(start: new ThreadStart(OtherThread1));
  other1.Start();
  
  パラメータ用ThreadStartデリゲートにメソッドを指定
  Thread other2 = new Thread(start: OtherThread1);
  other2.Start();
  
  ラムダ式
  Thread other3 = new Thread(() => OtherThread1());
  other3.Start();
}

public static void OtherThread1()
{
  for (int i = 0; i < 10; i++)
  {
    Console.WriteLine(@”Other!”);
  }
}

var myTask = new Task(() => {
 非同期処理
});
myTask.Start();

new Task( () =>
{
 非同期処理
}).Start();

Task.Run(() =>
{
 非同期処理
});

var ret = Task.Run(() =>
{
 非同期処理
 return 5;
});

ret.Result:5

static async Task<string> myAsyncAwait()
{
 await Task.Run(() =>
 {
  非同期処理
 });
 return @"AAA";
}

var ret = myAsyncAwait().Result;
ret:AAA

Action func = async () =>
{
 await Task.Run(() =>
 {
  非同期処理
 });
};

func();

var html = Task.Run(async () => {
 return await new HttpClient().GetStringAsync(@"https://office-yone.com/");
});

html.Result:<html>~

Windowsコントロールへの非同期処理反映

SampleAsync();
Invoke等の処理は不要

public async void SampleAsync() {
 this.Windowsコントロール.~ = "実行中";
 await Task.Run( () => {
  非同期処理
 } );
 this.Windowsコントロール.~ = "完了";
}

public class ThreadA extends Thread{
 @Override
 public void run(){
  try{
   for (int i=0; i<10; i++){
    System.out.println( "A" );
    Thread.sleep(100);
   }
  }catch(InterruptedException e){
   System.out.println(e.getMessage());
  }

 }
}

public class ThreadB extends Thread{
 public void run(){
  try{
   for (int i=0; i<10; i++){
    System.out.println( "B" );
    Thread.sleep(100);
   }
  }catch(InterruptedException e){
   System.out.println(e.getMessage());
  }

 }
}

public class App{
 public static void main( String[] args )<{
  new ThreadA().start();
  new ThreadB().start();
 }
}

→A B B A A B B A A B A B B A B A B A A B

public class ThreadA implements Runnable{
 public void run(){
  try{
   for (int i=0; i<10; i++){
    System.out.println( "A" );
    Thread.sleep(100);
   }
  }catch(InterruptedException e){
   System.out.println(e.getMessage());
  }

 }
}

public class ThreadB implements Runnable{
 public void run(){
  try{
   for (int i=0; i<10; i++){
    System.out.println( "B" );
    Thread.sleep(100);
   }
  }catch(InterruptedException e){
   System.out.println(e.getMessage());
  }
 }
}

public class App{
 public static void main( String[] args ){
  new Thread(new ThreadA()).start();
  new Thread(new ThreadB()).start();
 }
}

→A B B A B A B A A B B A B A B A A B A B

別スレッド呼び出し(引数有り)

以下の内容は現在ではメリット無し
非同期処理はスレッドプール(Taskクラス)を使う。

  ラムダ式
  Thread other4 = new Thread(() => OtherThread2(@”4″));
  //other4.Start();

  匿名メソッド
  new Thread(start: delegate()
  {
    OtherThread2(“5”);
  }).Start();

  パラメータ用ThreadStartデリゲートに引数を渡す
  Thread other6 = new Thread(start: OtherThread3);
  other6.Start(parameter: @”6″);

  for (int i = 0; i < 10; i++)
  {
    Console.WriteLine(@”Main!”);
  }
}

static void OtherThread2(string msg)
{
  for (int i = 0; i < 10; i++)
  {
    Console.WriteLine(msg);
  }
  Console.ReadKey();
}

static void OtherThread3(object msg)
{
  ※ パラメータ用ThreadStartデリゲートに引数の引数は変換が必要
  string myMsg = (string)msg;
  for (int i = 0; i < 10; i++)
  {
    Console.WriteLine(myMsg);
  }
  Console.ReadKey();
}

public class MyThread extends Thread{
 private String _s;
 public MyThread(String s){
  this._s = s;
 }
 public void run(){
  System.out.println( this._s );
 }
}

public class App{
 public static void main( String[] args ){
  new MyThread("Java").run();
 }
}

public class MyThread implements Runnable{
 private String _s;
 public MyThread(String s){
  this._s = s;
 }
 public void run(){
  System.out.println( this._s );
 }
}

public class App{
 public static void main( String[] args ){
  new Thread(new MyThread("Java")).start();
 }
}

スレッドの終了を待つ

using System.Threading.Tasks;

var myTask = new Task( () =>
{
 Console.WriteLine("myTask : start");
 System.Threading.Thread.Sleep(1000);
 Console.WriteLine("myTask : end");

});

Console.WriteLine("program : start");
myTask.Start(); タスク開始
myTask.Wait(); タスクの終了を待つ
Console.WriteLine("program : end");


program : start
myTask : start
myTask : end
program : start

非同期処理が成功してから処理を開始する
var myTask = new Task(() =>
{
 Console.WriteLine("myTask1 : start");
 System.Threading.Thread.Sleep(5000);
 Console.WriteLine("myTask1 : end");

});

myTask.Start();
↑ スレッドの終了後に開始
myTask.ContinueWith(_ =>
{
 Console.WriteLine(@"myTask was finished.");
});

Console.WriteLine(@"program : end");
↑ スレッドの終了を待たずに実行される。
↑ スレッドは非同期

var myTask = new Task(() =>
{
 Console.WriteLine("myTask1 : start");
 System.Threading.Thread.Sleep(5000);
 Console.WriteLine("myTask1 : end");

});

myTask.Start();
myTask.ContinueWith(_ =>
{
 Console.WriteLine(@"myTask was finished.");
});
↑ スレッドの終了を待つ。
Task.WaitAll(myTask);
Console.WriteLine(@"program : end");

複数のスレッドの終了を待つ

var myThread1 = new Thread( () =>
{
 Console.WriteLine("myThread1 : start");
 System.Threading.Thread.Sleep(1000);
 Console.WriteLine("myThread1 : end");

});

var myThread2 = new Thread(() =>
{
 Console.WriteLine("myThread2 : start");
 System.Threading.Thread.Sleep(2000);
 Console.WriteLine("myThread2 : end");

});

Console.WriteLine("program : start");
myThread1.Start();
myThread2.Start();

myThread1.Join();
myThread2.Join();

Console.WriteLine("program : end");
スレッドが2つとも終了してから処理される

※タスククラスを使用した場合1
using System.Threading.Tasks;

var myTask1 = new Task(() =>
{
 Console.WriteLine("myTask1 : start");
 System.Threading.Thread.Sleep(1000);
 Console.WriteLine("myTask1 : end");

});

var myTask2 = new Task(() =>
{
 Console.WriteLine("myTask2 : start");
 System.Threading.Thread.Sleep(2000);
 Console.WriteLine("myTask2 : end");

});

Console.WriteLine("program : start");
myTask1.Start();
myTask2.Start();
Task.WaitAll(myTask1, myTask2);

Console.WriteLine("program : end");
スレッドが2つとも終了してから処理される

※タスククラスを使用した場合2
using System.Threading.Tasks;

Parallel.Invoke(() =>
{
 Console.WriteLine("myTask1 : start");
 System.Threading.Thread.Sleep(1000);
 Console.WriteLine("myTask1 : end");

},
() =>
{
 Console.WriteLine("myTask2 : start");
 System.Threading.Thread.Sleep(2000);
 Console.WriteLine("myTask2 : end");

});

Console.WriteLine("program : end");
スレッドが2つとも終了してから処理される

排他制御

複数のスレッドから共通のリソース(データ)にほぼ同時にアクセスする事によるデータの不整合を制御する事

using System.Threading.Tasks;

非同期処理をロックしない場合
static void myThread(int prm)
{
 Console.WriteLine(@"[");
 Thread.Sleep(prm * 1000);
 Console.WriteLine(@"]");
}

static void Main(string[] args)
{

 Parallel.Invoke(
  () => myThread(prm: 1),
  () => myThread(prm: 2)
 );
}
→ [ [ ] ]

非同期処理をロックする場合
private static object myLock = new object();
static void myThread(int prm)
{
 lock (myLock)
 {
  Console.WriteLine(@"[");
  Thread.Sleep(prm * 1000);
  Console.WriteLine(@"]");
 }
}

static void Main(string[] args)
{

 Parallel.Invoke(
  () => myThread(prm: 1),
  () => myThread(prm: 2)
 );
}
→ [ ] [ ]

public class FamilyTread extends Thread {
 private Bathroom room;
 private String name;

 public FamilyTread(Bathroom room, String name) {
  this.room = room;
  this.name = name;
 }

 public void run() {
  this.room.in(this.name);
 }
}

public class Bathroom {
 synchronized付与により、メソッドを同時呼び出し不可に
 public synchronized void in(String name) {
  System.out.println(name + ":enter");
  try {
   System.out.println(name + ":enterd");
   3秒待機
   Thread.sleep(3000);
  } catch (InterruptedException e) {
   
  }
  System.out.println(name + ":out");
 }

}

public class Main {
 public static void main(String[] args) {
  Bathroom room = new Bathroom();

  FamilyTread father = new FamilyTread(room, "父");
  FamilyTread mother = new FamilyTread(room, "母");
  FamilyTread sister = new FamilyTread(room, "姉");
  FamilyTread me = new FamilyTread(room, "自分");

  father.start();
  mother.start();
  sister.start();
  me.start();
 }
}

結果:synchronized無
母:enter
父:enter
姉:enter
自分:enter
姉:enterd
姉:out
父:enterd
父:out
母:enterd
母:out
自分:enterd
自分:out

結果:synchronized有
父:enter
父:enterd
父:out
自分:enter
自分:enterd
自分:out
姉:enter
姉:enterd
姉:out
母:enter
母:enterd
母:out

並列処理

using System.Threading;

Parallel.For(0, 10, (n) =>
{
 Console.WriteLine(n);
});
→0~9まで数字が出力されるが毎回結果が異なる
(出力に関して並列で処理が行われている)

ForEach利用
var ary = Enumerable.Range(start: 0, count: 10);
Parallel.ForEach(ary, n => {
 Console.WriteLine(n);
});

LINQの並列処理(PLINQ)
static void Main(string[] args)
{
 var oldAry = Enumerable.Range(start: 0, count: 10);
 
 var newAry1 = oldAry.Where(n => n > retNum()).Select(n => n).ToArray();
 時間は掛かるが0~9が順番通り格納される
 var newAry2 = oldAry.Where(n => n > retNum()).AsParallel().Select(n => n).ToArray();
 0~9がバラバラに格納される(並列で処理される)。
 var newAry3 = oldAry.Where(n => n > retNum()).AsParallel().AsOrdered().Select(n => n).ToArray();
 時間は掛かるが0~9が順番通り格納される(並列で処理されるがソートされる)。
}

時間を掛けて0を返すだけの関数
static int retNum()
{
 Thread.Sleep(millisecondsTimeout: 1000);
 return 0;
}

タイマー

フォームコントロールのタイマーとは別。
処理が軽い。

using System.Threading;

private delegate void _delegate();
※フォーム操作用
private System.Threading.Timer _timer();
※タイマーオブジェクトは外部に保持しておかないとガーベージコレクションの対象となる

private void MyForm_Load(object sender, EventArgs e)
{
  定期的に実行する処理を指定(callBackMethod)
  TimerCallback timerDelegate = new TimerCallback(callBackMethod);
  
  タイマー実行
  _timer = new System.Threading.Timer(
    callback: timerDelegate,  
    state: null,
    dueTime: 0,
    period: 1000);
}

定期的に実行される処理
private void callBackMethod(object o)
{
  処理
  処理
  
  フォームを操作する場合
  Invoke(method: new _delegate(method));
}

/複数行に渡る処理を行う場合
private void method()
{
  this.MyLabel.Text = “フォーム操作”;
}

IAsyncResultクラス利用による非同期処理

内部的にスレッドプールを使用している為処理が軽くなる。

基本

移譲オブジェクト
delegate string SampleDelegate(int prm1, string prm2);

static void Main(string[] args)
{
  移譲オブジェクト作成
  SampleDelegate sd = new SampleDelegate(DelegateMethod);

  非同期処理開始
  IAsyncResult ar = sd.BeginInvoke(prm1: 100, prm2: @”test”, callback: null, @object: null);

  非同期処理終了
  string result = sd.EndInvoke(result: ar);
}

非同期で実行させる(重たい)処理
static string DelegateMethod(int prm1, string prm2)
{
  return “”;
}

待ち合わせ・待機

移譲オブジェクト
delegate string SampleDelegate(int prm1, string prm2);

static void Main(string[] args)
{
  移譲オブジェクト作成
  SampleDelegate sd = new SampleDelegate(DelegateMethod);

  非同期処理開始
  IAsyncResult ar = sd.BeginInvoke(prm1: 100, prm2: @”test”, callback: null, @object: null);

  非同期処理を2秒中断
  ar.AsyncWaitHandle.WaitOne(millisecondsTimeout: 2000);

  非同期処理終了まで待機
  ar.AsyncWaitHandle.WaitOne();

  if (ar.IsCompleted)
  {
    非同期処理終了
    string result = sd.EndInvoke(result: ar);       
  }
}

非同期で実行させる(重たい)処理
static string DelegateMethod(int prm1, string prm2)
{
  return “”;
}

コールバック関数利用

移譲オブジェクト
delegate string SampleDelegate(int prm1, string prm2);

static void Main(string[] args)
{
  移譲オブジェクト作成
  SampleDelegate sd = new SampleDelegate(DelegateMethod);

  コールバック関数定義
  AsyncCallback cb = new AsyncCallback(CallBackMethod);

  非同期処理開始
  IAsyncResult ar = sd.BeginInvoke(prm1: 100, prm2: @”test”, callback: cb, @object: null);

  非同期処理終了
  string result = sd.EndInvoke(result: ar);
}

非同期で実行させる(重たい)処理
static string DelegateMethod(int prm1, string prm2)
{
  Console.WriteLine(“asynchronous”);
  Console.ReadKey();
  return “”;
}

static void CallBackMethod(IAsyncResult ar)
{
  Console.WriteLine(“callback”);
  Console.ReadKey();
}

スレッド関連メソッド/プロパティ

別スレッドを開始
Thread インスタンス = new Thread(start: new ThreadStart(メソッド名));
インスタンス.Start();

※別スレッドで起動できるのは戻り値無し、引数無しのメソッドのみ
 戻り値やパラメータを利用したいときは、後述のデリゲートを使用

バックグラウンド・スレッド
メインのスレッドが終了すると自身も終了するスレッド

フォアグラウンド・スレッド
メインのスレッドが終了しても終了しないスレッド

バックグラウンド・スレッドとする
インスタンス.IsBackground = true;

優先度変更
インスタンス.Priority = ThreadPriority.Highest;
インスタンス.Priority = ThreadPriority.Normal;
インスタンス.Priority = ThreadPriority.Lowest;

スレッドの一時停止
インスタンス.Suspend();

スレッドの再開
インスタンス.Resume();

スレッドの処理が終了するまで待つ
インスタンス.Join();

スレッドの強制終了
インスタンス.Abort();

1秒間待つ
Thread.Sleep(1000);

プログラム言語 外部プログラム連携

概要

必要な機能が大きく、開発に要する時間が短い昨今、
プログラムの全てを自分で開発するのは効率が悪い。
他人が作ったプログラムをソースでなくDLLのまま利用する為の方法。
他言語で開発されたプログラムであってもそれは可能。

参考

Windowsはなぜ動くのか
Windowsの仕組み(.NET Frameworkとは?)
Windowsプログラミング

マーシャリング

異なるシステムへデータを渡す場合に渡し先で有効な型へ変換すること。
マネージ環境のプログラムから、アンマネージ環境で動作するプログラムを呼び出す際にマーシャリングが必要になる。

マーシャラー

マーシャリングを行うプログラム。

マネージ環境

CLR(CommonLanguageRuntime)によって管理された環境。
ガーベッジコレクション、セキュリティ機能等の.NetFrameworkの機能を提供する実行エンジン。
ガーベッジコレクションの動作を含むメモリ管理、配列・文字列の長さ管理が自動で行われる。

アンマネージ環境

上記以外の環境。
Win32API、COMオブジェクト、C/C++等、多言語で作られたプログラム等。
バッファがオーバーフローしない様、ガーベッジコレクションの動作に該当する使い終わったメモリの破棄等の処理は自動では行われない。

COM相互運用

マーシャリングを行った上で.NetFramework←→WindowsAPIでデータをやり取りを行う事。

ウィンドウハンドル

WindowsAPIにおいて操作対象毎に割り振られる管理番号
操作対象へのポインタ

実例

DLL(API)

APIとは?
Windowsプログラミング/API」参照

using System.Runtime.InteropServices;

class MyWin32
{
  [DllImport("USER32.DLL", EntryPoint = "MessageBoxA")]
  public static extern int myMessageBox(
    int hWnd,
    String lpText,
    String lpCaption,
    uint uType);
  
  ※USER32.DLLにおけるMessageBoxAをmyMessageBoxとして宣言
  
  public const int MB_OK = 0x00000000;
  public const int MB_OKCANCEL = 0x00000001;
  public const int MB_ABORTRETRYIGNORE = 0x00000002;
  public const int MB_YESNOCANCEL = 0x00000003;
  public const int MB_YESNO = 0x00000004;
  public const int MB_RETRYCANCEL = 0x00000005;

}

public partial class MyForm : Form
{
  private void MyForm_Load(object sender, EventArgs e)
  {

    MyWin32.myMessageBox(
      hWnd: 0,
      lpText: "メッセージ",
      lpCaption: "キャプション",
      uType: MyWin32.MB_YESNO);
  }
}

VB外部の関数(Windows API/DLL)を呼び出す場合に定義
Public Declare Auto Function GetUserNameA Lib "advapi32" (ByVal buf as string, size as long) As Long

Public Declare Auto Function(又はSub) [VBで使う関数名]
Lib "[DLLファイル名]"
Alias "[DLL内の実際のファイル名]" ([ファイルの引数]) As [戻り値の型]

Lib:DLLファイルを指定。拡張子を抜きもOK

Alias:DLL 内の関数名と別名で呼び出すことができる。指定無しも可
Public Declare Function GetUserName Lib "advapi32" Alias "GetUserNameA" (ByVal buf as string, size as long) As Long
Call GetUserName(引数)

Declare 定義した後は、通常の関数と同じに呼び出せる。
尚、Windows API や C で作られた DLL のパラメタは一般に値渡しなので、ByVal キーワードが必要。

VB外部の関数(Windows API/DLL)を呼び出す場合に定義
Public Declare Function GetUserNameA Lib "advapi32" (ByVal buf as string, size as long) As Long

Public Declare Function(又はSub) [VB.NETで使う関数名]
Lib "[DLLファイル名]"
Alias "[DLL内の実際のファイル名]" ([ファイルの引数]) As [戻り値の型]

Lib:DLLファイルを指定。拡張子を抜きもOK

Alias:DLL 内の関数名と別名で呼び出すことができる。指定無しも可
Public Declare Function GetUserName Lib "advapi32" Alias "GetUserNameA" (ByVal buf as string, size as long) As Long
Call GetUserName(引数)

Declare 定義した後は、通常の関数と同じに呼び出せる。
尚、Windows API や C で作られた DLL のパラメタは一般に値渡しなので、ByVal キーワードが必要。

Private Declare Function 公開名 Lib "DLL名" Alias "別名" (ByVal 引数1 As Long, ・・・) As Long
Private Declare Function 公開名 Lib "DLL名" Alias "別名" () As Long
Private Declare Function 公開名 Lib "DLL名" () As Long

Private Declare Sub 公開名 Lib "DLL名" Alias "別名" (ByVal 引数1 As Long, ・・・)
Private Declare Sub 公開名 Lib "DLL名" (ByVal 引数1 As Long, ・・・)
Private Declare Sub 公開名 Lib "DLL名" ()
※DLL名:DLLは実行ファイルと同階層に配置するか、パスを記載する。

Dim myApi As Long
myApi = 公開名(5,5)
Call 別名(5,5)

DLL(ActiveX)

ActiveXとは?
Windowsプログラミング/API」参照

Dim myObj As Object
myObje = CreateObject("~")
Call myObje.メソッド(~)
myObje.プロパティ = ~
DLL(COM)

COMとは?
Windowsプログラミング/COM」参照

「参照設定」によるDLLのパス設定が必要
COMコンポーネントでないDLLは参照設定できない。
DLLのCOM登録は「.NETで作成したDLLをVB6から呼び出す方法」参照

Dim myObj As New ~
Call myObje.メソッド(~)
myObje.プロパティ = ~

EXE

非同期で起動。※呼び出し元PGは実行されたまま。

' メモ帳を起動する
Call Shell("Notepad", vbNormalFocus)

' タスクIDを取得(≠Windowsハンドル)
Dim RetVal As Variant
RetVal = Shell("notepad", vbNormalFocus)
' Windowをアクティブに(≠最小化解除)
Call AppActivate(RetVal)

' ファイルを指定してメモ帳を起動する
Call Shell("Notepad C:\test.txt", vbNormalFocus)

' 引数がスペースを含む場合
Call Shell("""~.exe"" ""2015/05/08 10:00:00""", vbNormalFocus)

vbHide(0)
フォーカスを持ち、非表示
vbNormalFocus(1)
フォーカスを持ち、元のサイズと位置に復元
vbMinimizedFocus(2)
フォーカスを持ち、最小化表示
vbMaximizedFocus(3)
フォーカスを持ち、最大化表示
vbNormalNoFocus(4)
フォーカスを持たず、最後にウィンドウを閉じたときのサイズと位置に復元
※現在アクティブなウィンドウは、アクティブのまま
vbMinimizedNoFocus(6)
フォーカスを持たず、最小化表示
※現在アクティブなウィンドウは、アクティブのまま

System.Diagnostics.Process p =
  System.Diagnostics.Process.Start("notepad.exe");

//コマンドライン引数に「"C:\test\1.txt"」を指定してメモ帳を起動する
System.Diagnostics.Process.Start("notepad.exe", @"""C:\test\1.txt""");

プロセスの終了を検知する

using System.Diagnostics;

static void Main()
{
  // プログラムを起動しプロセスのインスタンスを取得
  Process hProcess = Process.Start(
    fileName: @"C:\Test.exe",
    arguments: @"prm1 prm2 prm3");
  
  // ↑プロセスが終了した時にExitedイベントを発生させる
  hProcess.EnableRaisingEvents = true;
  
  // Exitedイベントのハンドラを追加する
  hProcess.Exited += new System.EventHandler(Test_Exited);
  
  // 監視の為にアプリケーションを起動させておく必要あり。
  // タスクバーには表示されないがプロセスは起動する
  Application.Run();
}

private static void Test_Exited(object sender, System.EventArgs e)
{
  プロセス終了時、ここが呼ばれる
}

プログラム言語 正規表現

概要

通常の文字列判定(Perl)
fnMatchCheck("I Love Perl");
→マッチ
fnMatchCheck("I love perl");
→マッチしない
sub fnMatchCheck
{
  my $target = shift;
  if ($target eq "I Love Perl")
  {
    print "マッチ!","\n";
  }
}

正規表現を用いた判定(Perl)
fnMatchCheck("I Love Perl");
→マッチ
fnMatchCheck("I love perl");
→マッチ
sub fnMatchCheck
{
  my $target = shift;
  if ($target =~ /I [lL]ove [pP]erl/)
  {
    print "マッチ!","\n";
  }
}

基本形

using System.Text.RegularExpressions;

string[] strCheck = {
  @"C#", ⇒マッチ!
  @"c#",
  @"C",
  @"c",
  @"I Love C#", ⇒マッチ!
  @"VB.NET",
  @"Perl",
  @"abcde",
  @"abcC#de", ⇒マッチ!
  };

Regex myReg = new Regex(pattern: @"C#");

foreach (string elm in strCheck)
{
  //elm は "C#"を含むか?
  if (myReg.IsMatch(input: elm))
  {
    Console.WriteLine("マッチ!");
  }
}

@」はエスケープ処理防止
(「プログラム言語 変数/リテラル」参照)

文字列 =~ /検索語/
文字列 は 検索語 を含むか?

fnMatchCheck("I Love Perl");
→マッチ!

sub fnMatchCheck
{
  my $target = shift;
  # $target は Perl を含むか?
  if ($target =~ /Perl/)
  {
    print "マッチ!","\n";
  }
}

否定形
文字列 !~ /検索語/
文字列 は 検索語 を含まないか?

fnMatchCheck("I Love Perl");
→アンマッチ!

sub fnMatchCheck
{
  my $target = shift;
  # $target は Ruby を含まないか?
  if ($target !~ /Ruby/)
  {
    print "アンマッチ!","\n";
  }
}

正規表現

一覧

a*a

a、aa、9a、a9

表現 機能 使用例 結果
. 任意の1文字 a.a a9a、aaa
* 直前の1文字の0回以上の繰り返し
.* 直前の1文字の1回以上の繰り返し a.*a a99a、a9a、aaa、aa
+ 直前の1文字の1回以上の繰り返し a+a a99a、a9a、aa
? 直前の文字の0または1文字 a?a aaa、aa、9aa
^ 行の先頭 ^a aaa、aa、a9
$ 行の末尾 a$ aaa、aa、9a
[] カッコ内の任意の文字 [123]
[1-3]も可
a1、2a、a123b
[^] カッコ内の任意の文字以外 [^1-3] aa、9a
{n} n回繰り返し a{2} aa、aaa、9aa、aa9
{n,} n回以上繰り返し a{2,} aa、aaa、9aa、aa9
{n,m} n~m回繰り返し a{2,4} aa、aaa、aaaa、9aaa
~1|~2 ~1 または ~2 aa|99 aaa、a99、aab99
\ 直後の一文字を非正規表現として扱う \[、\?、\. [aa、a?、a.

メタキャラクタ

表現 機能
\w 英字 a~z、A~Z、_、1~9
\W 英字以外
\s 空白文字 半角スペース、タブ、改行、キャリッジリターン
\S 空白文字以外
\d 半角数字 0~9
\D 半角数字以外
\b 単語の境界

任意の一文字

[検索語]
検索語の中の一文字 を含むか?

string[] strCheck = {
  @"C#", ⇒マッチ!
  @"c#", ⇒マッチ!
  @"C", ⇒マッチ!
  @"c", ⇒マッチ!
  @"I Love C#", ⇒マッチ!
  @"VB.NET",
  @"Perl",
  @"abcde", ⇒マッチ!
  @"i love c#", ⇒マッチ!
  };

// elm は「c」か「C」を含むか?
Regex myReg = new Regex(pattern: @"[cC]");

foreach (string elm in strCheck)
{
  if (myReg.IsMatch(elm))
  {
    Console.WriteLine("マッチ!");
  }
}

文字列 =~ /[検索語]/
文字列 は 検索語の中の一文字 を含むか?

fnMatchCheck("I Love Perl");
→マッチ!
fnMatchCheck("I love perl");
→マッチ!

sub fnMatchCheck
{
  my $target = shift;
  # $target は p or P を含むか?
  if ($target =~ /[pP]/)
  {
    print "マッチ!","\n";
  }
}

任意の一文字(連続)
[ag]
⇒[abcdefg]

fnMatchCheck("c;);
→マッチ!

sub fnMatchCheck
{
  my $target = shift;
  # $target は abcdefg・・・vwxyz の中の一文字を含むか?
  if ($target =~ /[a-z]/)
  {
    print "マッチ!","\n";
  }
}

任意の一文字の否定
文字列 =~ /[^検索語]/
文字列 は 検索語の中の一文字 を含まないか?

fnMatchCheck("hijklmn");
→マッチ!

sub fnMatchCheck
{
  my $target = shift;

  # $target は abcdefg の中の一文字を含まないか?
  if ($target =~ /[^a-g]/)
  {
    print "マッチ!","\n";
  }
}

ワイルドカード(一文字)


何か一文字 を含むか?

string[] strCheck = {
  @"get", ⇒マッチ!
  @"gt",
  @"g",
  @"t",
  @"got", ⇒マッチ!
  @"ghost",
  @"I get pass" ⇒マッチ!
  };

// elm は 先頭「g」、間に何か一文字、末尾「t」の文字を含むか?
Regex myReg = new Regex(pattern: @"g.t");

foreach (string elm in strCheck)
{
  if (myReg.IsMatch(elm))
  {
    Console.WriteLine("マッチ!");
  }
}

文字列 =~ / ~~ /
文字列 は ~何か一文字~ を含むか?

fnMatchCheck("get");
→マッチ!
fnMatchCheck("ghost");
→マッチしない
fnMatchCheck("I’ve got a pass");
→マッチ!

sub fnMatchCheck
{
  my $target = shift;
  # $target は g(何か一文字)t を含むか?
  if ($target =~ /g.t/)
  {
    print "マッチ!","\n";
  }
}

量指定子

「?」(0個or1個)

string[] strCheck = {
  @"get", ⇒マッチ!
  @"gt", ⇒マッチ!
  @"g",
  @"t",
  @"got", ⇒マッチ!
  @"ghost",
  @"I get pass" ⇒マッチ!
  @"gto = great teacher onizuka"; ⇒マッチ!
  };

// elm は 先頭「g」、間に何か0文字or一文字、末尾「t」の文字を含むか?
Regex myReg = new Regex(pattern: @"g.?t");

foreach (string elm in strCheck)
{
  if (myReg.IsMatch(elm))
  {
    Console.WriteLine("マッチ!");
  }
}

文字列 =~ / ~? /
文字列 は ~を0文字か1文字 を含むか?

例:ab?
⇒「a」 または 「ab」にマッチ
例:a.?
⇒「a」 または 「ad」「ab」…「az」や、「a0」…「a9」にマッチ

fnMatchCheck("gt");
→マッチ!
fnMatchCheck("get");
→マッチ!
fnMatchCheck("ghost");
→マッチしない

sub fnMatchCheck
{
  my $target = shift;

  if ($target =~ /g.?t/)
  {
   # $target は g(何かの文字0文字か1文字)t を含むか?
    print "マッチ!","\n";
  }
}

「+」(1個以上)

string[] strCheck = {
  @"get", ⇒マッチ!
  @"gt",
  @"g",
  @"t",
  @"got", ⇒マッチ!
  @"ghost", ⇒マッチ!
  @"I get pass" ⇒マッチ!
  @"gto = great teacher onizuka";
  };

// elm は 先頭「g」、間に何か一文字以上、末尾「t」の文字を含むか?
Regex myReg = new Regex(pattern: @"g.+t");

foreach (string elm in strCheck)
{
  if (myReg.IsMatch(elm))
  {
    Console.WriteLine("マッチ!");
  }
}

文字列 =~ / ~+ /
文字列 は ~を1個以上 を含むか?

例:ab+
⇒「ab」「abb」「ab0」…にマッチ
例:a.+
⇒「aa」「ab」「abc」…にマッチ

fnMatchCheck("gt");
→マッチしない
fnMatchCheck("get");
→マッチ!
fnMatchCheck("ghost");
→マッチ!

sub fnMatchCheck
{
  my $target = shift;

  if ($target =~ /g.+t/)
  {
   # $target は g(何かの文字1個以上)t を含むか?
    print "マッチ!","\n";
  }
}

「*」(0個以上)

string[] strCheck = {
  @"get", ⇒マッチ!
  @"gt", ⇒マッチ!
  @"g",
  @"t",
  @"got", ⇒マッチ!
  @"ghost", ⇒マッチ!
  @"I get pass" ⇒マッチ!
  @"gto = great teacher onizuka"; ⇒マッチ!
  };

// elm は 先頭「g」、間に何か0文字以上、末尾「t」の文字を含むか?
Regex myReg = new Regex(pattern: @"g.*t");

foreach (string elm in strCheck)
{
  if (myReg.IsMatch(elm))
  {
    Console.WriteLine("マッチ!");
  }
}

文字列 =~ / ~* /
文字列 は ~を0文字以上 を含むか?

例:ab*
⇒「a」「ab」「abb」「ab0」…にマッチ
例:a.*
⇒「a」「aa」「ab」「abc」…にマッチ

fnMatchCheck("gt");
→マッチ!
fnMatchCheck("get");
→マッチ!
fnMatchCheck("ghost");
→マッチ!

sub fnMatchCheck
{
  my $target = shift;

  if ($target =~ /g.*t/)
  {
   # $target は g(何かの文字0個以上)t を含むか?
    print "マッチ!","\n";
  }
}

「{n}」(n個連続)
「{n,}」(n個以上連続)
「{n,m}」(n個以上m個以下連続)

string[] strCheck1 = {
  @"gt",
  @"get",
  @"geet",
  @"geeet" ⇒マッチ!,
  @"geeeet",
  @"g",
  @"t",
  @"ghost" ⇒マッチ!,
  @"I see ghost." ⇒マッチ!;
  };

// elm は 先頭「g」、間に何か三文字、末尾「t」の文字を含むか?
Regex myReg1 = new Regex(pattern: @"g.{3}t");

foreach (string elm in strCheck1)
{
  if (myReg1.IsMatch(elm))
  {
    Console.WriteLine("マッチ!");
  }
}

string[] strCheck2 = {
  @"gt",
  @"get", ⇒マッチ!
  @"geet", ⇒マッチ!
  @"geeet", ⇒マッチ!
  @"geeeet",
  @"g",
  @"t",
  @"ghost" ⇒マッチ!,
  @"I see ghost." ⇒マッチ!
  };

// elm は 先頭「g」、間に何か1~3文字、末尾「t」の文字を含むか?
Regex myReg2 = new Regex(pattern: @"g.{1,3}t");

foreach (string elm in strCheck2)
{
  if (myReg2.IsMatch(elm))
  {
    Console.WriteLine("マッチ!");
  }
}

string[] strCheck3 = {
  @"gt",
  @"get",
  @"geet",
  @"geeet", ⇒マッチ!
  @"geeeet", ⇒マッチ!
  @"g",
  @"t",
  @"ghost" ⇒マッチ!,
  @"I see ghost." ⇒マッチ!;
  };

// elm は 先頭「g」、間に何か三文字以上、末尾「t」の文字を含むか?
Regex myReg3 = new Regex(pattern: @"g.{3,}t");

foreach (string elm in strCheck3)
{
  if (myReg3.IsMatch(elm))
  {
    Console.WriteLine("マッチ!");
  }
}

文字列 =~ / ~{n} /
文字列 は ~をn個連続 を含むか?

例:ge{2}t
⇒「geet」にマッチ。get:×、gt:×

fnMatchCheck("get");
→マッチしない
fnMatchCheck("geet");
→マッチ!
fnMatchCheck("geeet");
→マッチしない

sub fnMatchCheck
{
  my $target = shift;

  if ($target =~ /ge{2}t/)
  {
    print "マッチ!","\n";
  }
}

位置指定子

「^」 先頭

例: "^\d"
"555" ○
"5aa" ○
"a55" ×

「$」 末尾

ただし、文字列の末尾が \n の時は、その前と一致。
(末尾が \n でも末尾で一致させるには、\z を使う。)

例: "\d$"
"555" ○
"aa5" ○
"55a" ×

代替構成体

①|②
①or②

置換

変数 =~ s/置換対象/置換後/;

my $s = "i love perl";
$s =~ s/i/I/;
⇒$s : I love perl

my $s = "I love perl";
$s =~ s/love/LOVE/;
$s =~ s/perl/PERL/;
⇒$s : I LOVE PERL

マッチした値の取得

if (文字列 =~ /(検索語)/)
{
  print "$1","\n";
  ⇒ 検索語
  # マッチした場合、検索語が$1に入る。
}

my $words_ref = [
  'papix loves meat!',
  'boolfool loves sushi!',
];

check($words_ref);

sub check
{
 my $str = shift;

 for my $elm (@$str)
 {
  if ($elm =~ /(.+) loves (.+)!/)
  {
   print "$1 => $2","\n";
   ⇒ papix => meat
   ⇒ boolfool => sushi
  }
 }
}

SQLでの利用

SQL DML:データ型/WHERE句における文字指定」参照

プログラム言語 ジェネリック

概要

設計時でなく、インスタンス作成時に型を決められる配列(クラス)
型だけ違って処理の内容が同じクラスを設計する際に用いる
ジェネリクス、ジェネリックス
(generic/generics)

ラッパークラス

ラップ(包む)
クラスの機能を利用する際に、
継承するのではなく、クラス内でそのクラスをインスタンス化&メソッドを呼び出し、
外部からは利用するクラスが見えない様に包み込む方法
class Other{
  void method(){ ~ }
}
class Mine{
  Other other;
  Mine(){
    this.other = new Other();
  }
  void method(){
    this.other.method();
  }
}
public static void main( ~ ){
  Mine mine = new Mine();
  mine.method();
  ※内部ではOther.method()が呼ばれている。
}
または、JAVAにおいて、基本型をObjectとして用いる為のクラス
ここではジェネリックに渡す引数
void method(Object obj)
  ~
}
method(引数);
※引数にはObject型を基底クラスとする型しか使えない
int等の基本型は×
Integer i = new Integer(100);
method(i);
は可。
なお、IDEの機能により結局直接数値を渡してもコンパイル可。

byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

汎用的な型

using System.Collections.Generic

//Tは汎用的な型(命名は自由)
public class MyList<T>
{
  T[] _list = new T[1000];
  
  public T this[int index]
  {
    get { return _list[index]; }
    set { _list[index] = value; }
  }
}

public void Form1_Load(object sender, EventArgs e)
{
  MyList<int> myList = new MyList<int>();
  ※T:intとしてインスタンスを作成
  
  for (var i = 0; i < 10; i++)
  {
    myList[i] = i;
    ※myList[i]にstring型の値を入れるとエラー
  }
}

【テンプレート】
コンパイル時にコードを生成する機能
型だけが異なる大量のコードを生成する時等に役立つ。

ベクターについては「プログラム言語 配列・リスト/リスト(コレクション)」参照

#include <vector>
#include <string>

汎用的な型:Tを定義
template <typename T>
class Stack
{
private:
  std::vector<T> stack_;
public:
  void Push(T value);
  T Pop();
  bool IsEmpty();
};

template <typename T>
void Stack<T>::Push(T value)
{
  this->stack_.push_back(value);
}

template <typename T>
T Stack<T>::Pop()
{
  T value = this->stack_.back();
  this->stack_.pop_back();
  return value;
}

template <typename T>
bool Stack<T>::IsEmpty()
{
  if (this->stack_.empty())
  {
    return true;
  }
  else
  {
    return false;
  }
}

int main(array<System::String ^> ^args)
{
  // インスタンス作成時に型を決められる

  Stack<std::string> *myStack = new Stack<std::string>();
  
  bool myBool = myStack->IsEmpty();
  // myBool:True
  myStack->Push("A");
  myStack->Push("B");
  myStack->Push("C");
  std::string myStr = myStack->Pop();
  // myStr:"C"
  myBool = myStack->IsEmpty();
  // myBool:False

  return 0;
}

Imports System.Collections.Generic

Public Class MyList(Of T)
  Dim _list(1000) As T
  
  Default Public Property list(ByVal index As Integer) As T
    Get
      Return _list(index)
    End Get
    Set(value As T)
      _list(index) = value
    End Set
  End Property
End Class

Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
  
  Dim myList As New MyList(Of Integer)
  ※T:Integerとしてインスタンスを作成
  
  For i As Integer = 0 To 10 Step 1
    myList(i) = i
    ※myList[i]にstring型の値を入れるとエラー
  Next i
  
End Sub

ジェネリッククラス
public class MyGeneric<T> {
 T t;
 public MyGeneric(T prmT){
  this.t = prmT;
 }
 public T getT(){
  return this.t;
 }
}
public class StudyMain {
 public static void main(String[] args) {

  MyGeneric<String> m1 = new MyGeneric<String>("java");
  String s = m1.getT();
  MyGeneric<Integer> m2 = new MyGeneric<Integer>(100);
  Integer i = m2.getT();
 }
}



ジェネリックメソッド
public class MyGeneric {
 public <T> T retT(T prmT){
  T t = prmT;
  return t;
 }
}

public class StudyMain {
 public static void main(String[] args) {

  MyGeneric m1 = new MyGeneric();
  String s = m1.retT("Java");
  MyGeneric m2 = new MyGeneric();
  int i = m2.retT(5);
 }
}



ジェネリックインターフェース
public interface MyInterface<T> {
 public T myMethod();
 public void myMethod(T t);
}

public class MyGeneric implements MyInterface<String> {
 @Override
 public String myMethod() {
  return "Java";
 }
 @Override
 public void myMethod(String t) {
  ~
 }
}

public class StudyMain {
 public static void main(String[] args) {
  MyGeneric m = new MyGeneric();
  String s = m.myMethod();
  m.myMethod("Java");
 }
}

静的ジェネリッククラスコンストラクタ

static class MyClass<T>
{
 public static T myValue { get; set; }
 static MyClass()
 {
  Console.WriteLine(@"初期化");
 }
}

MyClass<string>.myValue = @"aaa";
MyClass<int>.myValue = 100;
MyClass<string>.myValue = @"bbb";
Console.WriteLine(MyClass<string>.myValue);
Console.WriteLine(MyClass<int>.myValue);


初期化 ※T=string時
初期化 ※T=int時
bbb
100
※最初の使用時のみコンストラクタが実行される。

制約

基本クラス制約

型(T)=基本クラス(基底クラス)

using System.Collections.Generic;

class Parent
{
 public string pFunc(string str) { return str; }
}

class Child : Parent { }

class Other {}

型(T)=基本クラス
class Test<T> where T : Parent
{
 T obj;
 public Test(T o) { this.obj = o; }
 T はParent型。o はParentのインスタンス
 public void testFunc(string prm)
 {
  string revStr = this.obj.pFunc(str: prm);
  this.objはParentのインスタンスなので、Parentのメンバー関数を呼び出し可能
  Console.WriteLine(revStr);
 }
}

class Program
{
 static void Main(string[] args)
 {

  Parent p = new Parent();
  Child c = new Child();
  
  Test<Parent> t1 = new Test<Parent>(o: p);
  t1.testFunc(prm: @"aaa");
  
  基本クラス制約の型(クラス)は派生クラスでもOK
  Test<Child> t2 = new Test<Child>(o: c);
  t2.testFunc(prm: @"aaa");
  
  Other o = new Other();
  Test<Other> t3 = new Test<Other>(o: o);
  →コンパイルエラー:Parentを継承していないクラスを型パラメータとして指定できない
  
  Test<string> t3 = new Test<string>(o: @"aaa");
  →コンパイルエラー:Parentを継承していないクラスを型パラメータとして指定できない

 }
}

public class MyGeneric<T extends Number> {
 public T myMethod() {
  T t = null;
  return t;
 }
 public void myMethod(T t) {
  ~
 }
}

public class StudyMain {
 public static void main(String[] args) {
  MyGeneric<Integer> m1 = new MyGeneric<Integer>();
  int i = m1.myMethod();
  m1.myMethod(100);
  m1.myMethod(5.5); →エラー

  MyGeneric<Double> m2 = new MyGeneric<Double>();
  Double d = m2.myMethod();
  m2.myMethod(5.5);
  m2.myMethod(100); →エラー

  MyGeneric<String> m1 = new MyGeneric<String>(); →エラー
 }
}

ワイルドカード
public class X{
 public String toString(){
  return "X";
 }
}

public class Y extends X{
 public String toString(){
  return "Y";
 }
}

public class Main {

 list = X、またはXの子クラス
 public static void method1(List<? extends X> list){

  実行時まで型不明の為、型を指定したaddはコンパイルエラー
  list.add(new X()); エラー
  list.add(new Y()); エラー
  System.out.println(list.get(0));
 }

 list = Y、またはYの親クラス
 public static void method2(List<? super Y> list){
  実行時まで型不明の為、型を指定したaddはコンパイルエラー
  list.add(new X()); エラー
  list.add(new Y()); YはOK
  System.out.println(list.get(0));
  System.out.println(list.get(1));
 }

 public static void main(String[] args) {
  List<X> l1 = new ArrayList<>(); l1.add(new X());
  List<Y> l2 = new ArrayList<>(); l2.add(new Y());

  method1(l1); →X
  method1(l2); →Y

  method2(l1); →X Y
  method2(l2); →Y Y
 }
}

インターフェイス制約

型(T)=指定のインターフェイスを実装している型(クラス)

using System.Collections.Generic;

interface IParent
{
 string pFunc(string str);
}

class Child : IParent{ }

class Other {}

型(T)=インターフェイス
class Test<T> where T : IParent
{
 T obj;
 public Test(T o) { this.obj = o; }
 T はIParentを継承した型(クラス)。o はそのインスタンス
 public void testFunc(string prm)
 {
  string revStr = this.obj.pFunc(str: prm);
  this.objはIParentを継承したクラスのインスタンスなので、IParentのメンバー関数を呼び出し可能
  Console.WriteLine(revStr);
 }
}

class Program
{
 static void Main(string[] args)
 {

  Child c = new Child();
  Test<Child> t1 = new Test<Child>(o: c);
  t1.testFunc(prm: @"aaa");
  
  Other o = new Other();
  Test<Other> t2 = new Test<Other>(o: o);
  →コンパイルエラー:IParentを継承していないクラスを型パラメータとして指定できない
  
  Test<string> t3 = new Test<string>(o: @"aaa");
  →コンパイルエラー:IParentを継承していないクラスを型パラメータとして指定できない

 }
}

コンストラクタ制約

型(T)=デフォルトコンストラクタが実装されている型(クラス)

class MyClass1
{
 public MyClass1(string prm){}
}

class MyClass2
{
 public MyClass2(){}
 public MyClass2(string prm){}
}

class Test<T> where T : new()
{
 public Test()
 {
  T t = new T();
  コンストラクタ制約があるのでジェネリック型(クラス)のインスタンスを作成できる。
  制約が無ければコンパイルエラー

 }
}

static void Main(string[] args)
{

 Test<MyClass1> t1 = new Test<MyClass1>();
 MyClass1はデフォルトコンストラクタが定義されていないのでコンパイルエラー

 
 Test<MyClass2> t2 = new Test<MyClass2>();
 MyClass2はデフォルトコンストラクタがあるので多重定義があってもOK
}

参照型制約

型(T)=参照型

class Test<T> where T : class
{
 T obj;
 public Test(T prm)
 {
  this.obj = prm;
 }
}

static void Main(string[] args)
{

 Test<string> t = new Test<string>(prm: @"aaa");
 Test<string> t = new Test<string>(prm: null);
 Test<string> t = new Test<string>(prm: string.Empty);
 Test<MyClass> t = new Test<MyClass>(prm: new MyClass());
 Test<Test<string>> t = new Test<Test<string>>(prm: new Test<string>(prm: @"aaa"));

 ↓ コンパイルエラー
 Test<int> t = new Test<int>(prm: 5);
 Test<bool> t = new Test<bool>(prm: true);

}

値照型制約

型(T)=値型

class Test<T> where T : struct
{
 T obj;
 public Test(T prm)
 {
  this.obj = prm;
 }
}

struct MyStruct
{
 public int myInt;
}

class MyClass { }

static void Main(string[] args)
{

 Test<int> t = new Test<int>(prm: 5);
 Test<bool> t = new Test<bool>(prm: true);
 Test<MyStruct> t = new Test<MyStruct>(prm: new MyStruct() { myInt = 5 });
 
 ↓ コンパイルエラー
 Test<string> t = new Test<string>(prm: string.Empty);
 Test<MyClass> t = new Test<MyClass>(prm: new MyClass());

}

制約の順番

(1)→(3)の順で記述
(1)参照型制約、値型制約、基本クラス制約
どれか1つだけ
(2)インターフェイス制約
(3)コンストラクタ制約

interface IMyInterface{}
class MyClass{}

○:class Test<T> where T : MyClass, new() { }
○:class Test<T> where T : class, IMyInterface, new() { }
×:class Test<T> where T : IMyInterface, MyClass, new() { } ※順序違反
×:class Test<T> where T : new(), MyClass, IMyInterface { } ※順序違反
×:class Test<T> where T : class, struct { } ※(1)重複違反

複数の型パラメーターに別の制約を付ける場合
class Test<T1, T2>
 where T1 : class
 where T2 : struct
{ }

プログラム言語 クロージャ

概要

※関数内でローカル変数を参照している関数

//クロージャ(ローカル変数:prmIntを参照している)
function Closure(prmInt) {
  return function() {
    alert(–prmInt);  //-1
  }
}

var myFunc1 = Closure(10);  //関数Closureそのものを格納
var myFunc2 = Closure(10);  //関数Closureそのものを格納

alert(myFunc1);
//myFunc1(=Closure)を実行して表示⇒9(prmInt初期値:10)

alert(myFunc1);
//myFunc1(=Closure)を実行して表示⇒8(prmInt初期値:9)

alert(myFunc2);
//myFunc2(=Closure)を実行して表示⇒9(prmInt初期値:10)

var Timer = window.setTimeout("Closure()",1000)
//1秒後にClosure()を実行・・・○ 引数のない関数はこれでOK

var Timer = window.setTimeout("Closure(10)",1000)
//1秒後にClosure(10)を実行・・・×

var Timer = window.setTimeout(function(){
  Closure(10);
} ,1000)
//1秒後にClosure(10)を実行・・・○

プログラム言語 JSONデータ操作

概要

JavaScriptObjectNotesion
JavaScriptのオブジェクトを操作できる表記法を用いたデータ形式

表記法

(1) { キー : 値 , キー : 値 }
(2) キー、値、ともに「"」で囲む
{ "name": "John Smith", "age": 33 }
配列
[ "要素1", "要素2", "要素3" ]

読み込み

「プロジェクト」メニュー >「参照の追加」から以下を参照
System.Runtime.Serialization

[DataContract]
public class FriendInfo
{
  [DataMember]
  public string Name { get; set; }

  [DataMember]
  public string Address { get; set; }

  [DataMember]
  public int Age { get; set; }
}

using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;

private void Form1_Load(object sender, EventArgs e)
{
  //(1)読み込むJSONデータ
  var jsonString = @"{
      ""Address"" : ""Nishinomiya"",
      ""Age"" : 35,
      ""Name"" : ""Yone""
    }";

  //(2)DataContractJsonSerializerをインスタンス化
  var serializer = new DataContractJsonSerializer(type: typeof(FriendInfo));

  //(3)JSONデータを文字列からバイト配列に変換
  var jsonBytes = Encoding.Unicode.GetBytes(jsonString);

  //(4)バイト配列を読み込むMemoryStreamクラスを定義
  var sr = new MemoryStream(jsonBytes);

  //(5)ReadObjectメソッドでJSONデータを.NETオブジェクトに変換
  var obj = (FriendInfo)serializer.ReadObject(sr);
  ⇒
  obj.Name : Yone
  obj.Age : 35
  obj.Address : Nishinomiya

}

JSON→MAP
String s = "{\"return\":\"OK\",\"errorcode\":\"E90000\"}";

Map<String, String> map = new LinkedHashMap<String, String>();
ObjectMapper mapper = new ObjectMapper();

map = mapper.readValue(s, new TypeReference<LinkedHashMap<String, String>>(){});

for (Map.Entry<String, String> entity : map.entrySet()){
 String key = entity.getKey();
 key : return、errorcode
 String value = entity.getValue();
 value : OK、E90000
}
System.out.println(map);
→{return=OK, errorcode=E90000}

MAP→JSON
s = mapper.writeValueAsString(map);
System.out.println(s);
→{"return":"OK","errorcode":"E90000"}

書き込み

//↑ JSONデータを変更
obj.Address = "kobe";

var ms = new MemoryStream();
serializer.WriteObject(stream: ms, graph: obj);

jsonString = Encoding.UTF8.GetString(ms.ToArray());
jsonString : {“Address”:”kobe“,”Age”:32,”Name”:”Doi”}