【C#】valueがlistのDictionary
var mData = new Dictionary<string, List<string>>
{
{ "X", new List<string>() { "あ", "い", "う" } },
{ "Y", new List<string>() { "か", "き", "く" } },
{ "Z", new List<string>() { "さ", "し", "す" } }
};
var sData = new Dictionary<string, List<string>>
{
{ "X", new List<string>(){ "あ", "あ", "あ", "い", "う", "う" } },
{ "i", new List<string>(){ "subI1", "subI2", "subI3", "subI1", "subI1", "subI2" } },
{ "j", new List<string>(){ "subJ1", "subJ2", "subJ3", "subJ1", "subJ1", "subJ2" } }
};
var key = "X";
var mDataValueSize = mData.Max(kv => kv.Value.Count); // valueのlistの要素数は全て同一と仮定
var mSeq = Enumerable.Range(0, mainDataValueSize); // 第一引数は開始位置, 第二引数は個数で連続する配列
foreach (var m in mSeq) {
var keyValue = mData[key].ElementAt(m);
var sIndex = sData[key].IndexOf(keyValue);
var seq = sData[key].Where(kv => kv == linkingKeyValue).Count();
var subSeq = Enumerable.Range(sIndex, seq);
foreach (var s in subSeq) {
var oneRec = sData.ToDictionary(kv => kv.Key, kv => kv.Value.ElementAt(s));
}
}
【C#】継承
文法
class 派生クラス名 : 基底クラス{}
継承とは
派生クラスのインスタンスは暗黙的に基底クラスのインスタンスを持つ
このため、基底クラスのメンバにもアクセスすることができる
隠蔽
メンバの実体が1つに収束するわけではなく、基底クラスと派生クラスのメンバが重複している。
例)基底クラス
class MyBase
{
public void Exec() => System.Console.WriteLine("This is Base.");
}
例)派生クラス
class MyInheritance : MyBase
{
public void Exec() => System.Console.WriteLine("This is Inheritance.");
}
メンバの隠蔽では、基底クラスと派生クラスのメンバが重複しているため、どちらが使われるかは、型によって決定される。
class Program
{
static void Main()
{
MyBase mb = new MyInheritance();
mb.Exec(); // This is Base.
MyInheritance mh = new MyInheritance();
mh.Exec(); // This is Inheritance.
auto mh2 = new MyInheritance();
mh2.Exec(); // This is Inheritance.
}
}
明示的な隠蔽
コンパイラ(他の開発者にも)に意図した隠蔽であることを伝えるためには「new 修飾子」を用いる。
class MyInheritance : MyBase
{
public new void Exec() => System.Console.WriteLine("This is Inheritance");
}
継承の禁止
sealed class MyBase
{
public void Exec() => System.Console.WriteLine("This is Base.");
}
これで、以下のコードはエラーになる。
class MyInheritance : MyBase{}
多重継承の禁止
【文字コード】入門
文字コード(Character Code)
通常、7ビット(128通り)または8ビット(256通り)を最小単位とする。
文字集合
このとき、
- 文字群:レパートリ
- 一意の番号を与えたもの:符号化文字集合
代表的な符号化文字集合はJIS X 0201、JIS X 0208、Unicodeなど
Unicode
符号位置は4桁以上の16進数(例」U+20B9F)で、6桁の16進数で表したとき、最初の2桁を「面(00面~ff面)」、次の2桁を「区(00区~ff区)」、最後の2桁を「点(00点~ff点)」と呼ぶ
基本は「1文字=2バイト」だが、1部の文字は「1文字=4バイト」(サロゲートペア)
従来のUnicodeでは未使用だった0xD800~0xDBEF(1024通り)を上位サロゲート、0xDC00~0xDFFF(1024通り)を下位サロゲートとして、「上位サロゲート+下位サロゲート」の4バイトで文字を表現
例)ǹ
ベースとなる「n」の直後に合成用の「'」と付ける
符号化方式
JIS, Shift JIS, UTF-8, UTF-16, UTF-32
UTF-16
UTF-32
Unicodeの有効ビット数は21ビット弱なので、変換は不要で上位ビットを0埋めすれば良い
バイト列の変換については、ビッグエンディアンがデフォルトで、データの先頭にエンディアンを指定する「バイト順マーク」がつくことがある。
- ビッグエンディアン:00 00 FE FF
- スモールエンディアン:FF FE 00 00
UTF-8
1単位だけで、コードポイントを表現するときは、下位7bitはASCIIと等しく、ASCIIを使っていたコードやシステムと親和性が高く、最も普及しているエンコード
【Java】画像ファイルを2分割する
分割側コード
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import javax.imageio.ImageIO;
public class ImageDivided {
private InputStream inputStream;
public ImageDivided(InputStream inputStream) {
this.inputStream = inputStream;
}
public ArrayList<BufferedImage> GetDividedInto2(){
var ret = new ArrayList<BufferedImage>(2);
try{
var originalImage = ImageIO.read(this.inputStream);
var width = originalImage.getWidth();
var height = originalImage.getHeight();
var halfWidth = width / 2;
var leftHalfImage = originalImage.getSubimage(0, 0, halfWidth, height);
var rightHalfImage = originalImage.getSubimage(halfWidth, 0, halfWidth, height);
ret.add(leftHalfImage);
ret.add(rightHalfImage);
}catch(Exception e){
}
return ret;
}
}
使う側コード
import java.io.File;
import java.io.FileInputStream;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;
public static void main(String[] args){
var imageDivided = new ImageDivided(new FileInputStream(画像ファイル));
var ret = imageDivided.GetDividedInto2();
var writers = ImageIO.getImageWritersByFormatName("jpeg");
var writer = (ImageWriter)writers.next();
var outputStream = ImageIO.createImageOutputStream(new File(出力ファイル1));
writer.setOutput(outputStream);
writer.write(ret.get(0));
outputStream = ImageIO.createImageOutputStream(new File(出力ファイル2));
writer.setOutput(outputStream);
writer.write(ret.get(1));
}
【C#】Disposeパターン
using
ただし、メンバ等にはusingが使えない。。。⇒Disposeパターン
Dispose()の必須事項
- 安全に複数回呼び出し可能であること
- インスタンスが保持しているリソース(OSや外部DLLが管理するもの)を解放すること
- 必要ならば、基本クラスのDispose()を呼ぶこと
- このクラスのファイナライザを抑制して、GCがファイナライズキュー上のオブジェクト数を減らすための手助けをする
- 基本的に例外をスローしない
Disposeパターン
ベースクラス
解放処理はDispose(bool disposing)で行い、Dispose()とファイナライザをそれを呼び出す
サブクラス
例
public class Base : System.IDisposable
{
private bool isDisposed; // Disposeされたかを表すフラグ
public Dispose()
{
this.Dispose(true); // 解放処理はDispose(bool disposing)で行い、Dispose()とファイナライザをそれを呼び出す
System.GC.SuppressFinalize(this); // 二重解放を避ける
}
~Base()
{
this.Dispose(false); // 解放処理はDispose(bool disposing)で行い、Dispose()とファイナライザをそれを呼び出す
}
protected virtual void Dispose(bool dispose)
{
if (this.isDisposed) return; // 安全に複数回呼び出し可能
if (dispose)
{
// マネージリソースの解放(ex:ストリーム)
}
// アンマネージリソースの解放
this.isDisposed = true; // 安全に複数回呼び出し可能
}
}
【C#】環境系
環境変数の値を取得
var ret = System.Environment.GetEnvironmentVariable("環境変数名");
// 変数名があれば値、なければNULL
実行中のプログラムのexe/dllのパスを取得
var ret = System.Reflection.Assembly.GetExecutingAssembly(); // 実行中のアセンブリ
var path = System.IO.Path.GetDirectoryname(new System.Uri(ret.Location).LocalPath); // exe,dllのディレクトリ
【C#】ファイル系
存在チェック
System.IO.File.Exists("パス"); // Trueならファイルが存在
System.IO.Directory.Exists("パス"); // Trueならディレクトリが存在
パスがローカルか
var uri = new System.Uri("パス");
uri.IsLoopback; // Trueならローカル