デリゲート

デリゲート

メソッドへの参照を表す型(デリゲート型)
Delegateは委譲という意味で、委譲する内容は処理
定義方法は、処理を記述しない以外は、通常のメソッドと同様で、それにdelegateキーワードを指定する。
デリゲート型の変数には、戻り値と引数リストが一致するメソッドを代入できる(派生クラス(ダウンキャスト)は可能)
delegate 戻り値 デリゲート名(引数リスト);

マルチキャスト

+,-演算子で複数のメソッドを代入することができる。
複数のメソッドが代入されているデリゲートを呼び出すと、代入順に逐次実行される。

述語

デリゲートの主要な用途の1つで、条件を満たすかどうかを調べるメソッド(述語)を代入し、ほかのメソッドに渡す方法がある。

代入するメソッドについて

デリゲート型の変数に代入するメソッドは、クラス(static)メソッド、インスタンスメソッドのどちらでも代入することができる。
つまり、代入するメソッドの使用回数によらず、どこかに必ず1回は定義しなければならない。
C#では、これを簡単にする仕組みが存在する。
匿名関数
デリゲート用の仕組みで、後述するラムダ式はさらに簡素化されて、機能も充実している。(デリゲート以外の用途がある)
delegate (引数リスト){処理}
ラムダ式
関数を整数などの変数と同じように扱う。
一般的な定義は以下の①であるが、引数が明確な場合には②のように省略することができる。
(int n) => n > 0; // ①
n => n > 0; // ② 0と比較しているため、引数がint型であることは明確

まとめ

デリゲートの基礎をまとめるために、以下のプログラムを考える。
配列内の、5以上の偶数を表示する
internal class Summary
{
    private delegate bool DGCondition(int n);

    internal static void DispGT5Even(int[] nums)
    {
        DGCondition prediction = n => n >= 5;
        prediction += n => n % 2 == 0;
        GetGT5Even(nums, prediction);
    }

    private static void GetGT5Even(int[] nums, DGCondition prediction)
    {
        foreach (var num in nums)
        {
            var condition = prediction(num);
            condition &= prediction(num);
            if (!condition) continue;
            System.Console.WriteLine(num);
        }
    }
}

【Office Open XML】stylesのnumFmtについて

numFmtについて

 

ttkcd.hatenablog.com

 

に記載した通り、numFmts要素の子要素であるnumFmtは0ベースのインデックスではなく、numFmtのnumFmtIdを指定することによって参照される。
numFmtIdが同じだが、フォーマットが異なる値が存在した場合は?
numFmtの定義は以下の通り
<complexType name="CT_NumFmt">
  <attribute name="numFmtId" type="ST_NumFmtId" use="required"/>
  <attribute name="formatCode" type="ST_Xstring" use="required"/>
</complexType>
上記の通り、numFmtIdは同じだが、formatCodeが異なる場合は起きうる。
Excelで確認すると、後に定義された要素が適用される。

【C#】単体テスト

Visual Studio

公式としては、1プロジェクトに対応して1つの単体テストプロジェクトを推奨
以下のような、TargetProjectについて考える。
namespace TargetProject
{
  internal class InternalClz
  {
    public void PublicAdd(int a, int b) => a + b;
    internal void InternalAdd(int a, int b) => a + b;
    private void PrivateAdd(int a, int b) => a + b;
  }
}
対象のプロジェクトのソリューションで右クリック⇒[追加]⇒[新しいプロジェクト]⇒[MSTestテストプロジェクト] (※.NET Coreの場合)でプロジェクト(UnitTestProject)を作成

アクセス修飾子

上記のクラスはinternalなので、他のプロジェクトから呼び出すことが出来ない。
そこで、TargetProjectを以下のように修正する
#if DEBUG
using System.Runtime.CompilerServices;
[assembly: InternalVisibleTo("UnitTestProject")
#endif
namespace TargetProject
{
  internal class InternalClz
  {
    public void PublicAdd(int a, int b) => a + b;
    internal void InternalAdd(int a, int b) => a + b;
    private void PrivateAdd(int a, int b) => a + b;
  }
}
上記を追加することによって、Debug時に、対象のクラスをUnitTestProjectプロジェクトから呼び出すことが出来る

private

方法はありそうだが、今回は調査しない。
privateメソッドについては、要否の議論もあるが、自分は必要と思っている。
単体テストでの確認方法は、アクセス可能な他のメソッドからの確認で、カバー出来ないのならば不適切という方針がしっくりきた。

実際にテストしてみる

以下のメソッドを作成
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace UnitTestProject
{
  [TestClass()]
  public class InternalClzTests{
    InternalClz internalClz = new InternalClz();
    
    [TestMethod()]
    public void PublicAddTest()
    {
      Assert.AreEqual(internalClz.PublicAdd(3, 4), 7); // Assert.AreEqual(結果,期待値) ①
    }
    
    [TestMethod()]
    public void InternalAddTest()
    {
      Assert.AreEqual(internalClz.InternalAdd(3, 4), 7); // ②
      Assert.AreEqual(internalClz.InternalAdd(4, 4), 7); // ③
    }
  }
}
テストの簡単な実行方法は、対象のプロジェクトで右クリック⇒[テストの実行]
上記の場合③がエラーのため、×が表示される。(Assert.AreEqual failed, Expected:<7>.Actual:<8>

【Office Open XML】stylesパーツ

stylesパーツ

以下で、主要な要素について簡単な説明をしたが、いまいち分かりづらかったので、再度

 

ttkcd.hatenablog.com

 

styles.xml

SpreadSheetのワークシートのセルは、塗りつぶしをして色を設定したり、フォントを変えたりすることが出来る。
この情報をすべてのセル要素に記載するとファイルサイズが膨大になってしまうため、 stylesパーツを使用してワークブックのセルに適用されているスタイルの情報をまとめる

styleSheet(Style Sheet)要素

stylesパーツのルート要素
この子要素に、塗りつぶしやフォント情報が定義される。
子要素は11種類あるが、以下の4つに分類できる。
  • 将来の拡張用の要素
  • セル内部のスタイル情報
  • セル自身の情報
  • セル自身の情報2
上記の、将来の拡張用の要素は、extLst要素のみで、ここでは説明しない。

セル内部のスタイル情報

numFmts, fonts, fills, borders, tableStyles, colorsは大まかにここに分類できるように思える。
ワークブック全体で使用されているフォント情報等が、該当する各要素の子要素として定義されている。
少しわかりづらいのが、colors要素で、これはレガシーやカスタムされた色情報が子要素に定義される。
セル全体として、どれを使用するかは、セル自身の情報,セル自身の情報2の属性で、これらを指定する。
このとき、tableStyles, colorsは直接指定されず、例えばカスタムされた色が塗りつぶしに使用されていれば、これがfillsの子要素に定義される。
セル自身の情報,セル自身の情報2の属性は、numFmts要素以外は、子要素の0ベースのindexが対応する属性の値として指定される。
numFmt要素のみ、numFmtIdを持ち、対応する属性の値として指定される。

セル自身の情報

上記のスタイルのどれを使うかを指定している要素で、cellStyleXfs, cellXfs, cellStylesがここに分類できるように思える。
この3つの要素のうち最も基本となるのが、cellStyleXfs要素で、ワークブックで使用されている名前付きセルスタイルを定義している要素
次に、cellStyles要素が似たような要素で、cellStyleXfs要素からの少しの差を示す。実際にxfId属性で、cellStyleXfs要素の子要素の0ベースのインデックスを指定する
最後に、cellXfs要素で、シートのセル要素が参照する要素はこの要素の子要素で、参照方法は、0ベースのインデックス

セル自身の情報2

dxfs要素で、使用するセル内部のスタイル情報のみが定義されている。
条件付き書式設定で使用される要素で、ワークシートのcfRuleのdxfId属性が子要素の0ベースのインデックスで参照する

【Java】FileとPath(+Files)

FileクラスとPathインタフェース(+Filesクラス)のどちらを使えばよいのか

 

ttkcd.hatenablog.com

に書いたように、PathはFileで可能な操作は基本的に可能

はじめに、似たような機能を持つのにそもそもパッケージが異なる
Fileクラスがjava.ioなのに対して、Pathインタフェースはjava.nio.file
nはnewで、PathインタフェースはJava7で追加されたもの。つまり、Oracleはすでにある機能を改めて新しいAPIを作成した

結論

いかに主な違いを記載するが、基本的に新規のシステムではPathとFilesを使用したほうがよさそう
おそらく、Pathが追加されるタイミングで、FileクラスのtoPath()が追加された。
違い1(エラー処理)
それぞれを使用してファイルを削除する場合を考える。
var file = new File("");
var path = Paths.get("");
boolean isDeleted = file.delete(); // ①
Files.delete(path); // ②
上記のコードの場合、①は削除できたか否かを返すが、②はコンパイルエラー(IOExceptionの処理が必要)が発生する。
つまり、削除を試みたが削除できなかった原因がわかる。
違い2(メタデータ
ファイルには許可・所有者などのメタデータが含まれているが、Fileクラスはサポートされていない。Pathはサポートしている
例)ファイルの所有者:Files.getOwner(Path path, LinkOption... options)
違い3(パフォーマンス)
FileはPathに比べるとパフォーマンスが悪くなる場合がある。
例)ディレクトリに多数のファイルがあった場合

【Java】ファイル操作

Javaでのファイル操作

Fileクラス(java.io)

ファイルまたはディレクトリについての情報である抽象パス名をもとにファイルに関する様々な操作を行う
コンストラク
4つのコンストラクタが存在する。 情報はあくまで"抽象パス名"であるため、指定された値の存在有無は関係ない
また、A:\B:\のような不正なパス(空文字もOK)も問題なくインスタンス化可能
①のparentがnullの場合は、childがそのままパスとされ、それ以外はNullPointerException
File(File parent, String child)// ①
File(String pathname)// ②
File(String parent, String child)// ③
File(URI uri)// ④
③のコンストラクタでの区切り文字について、考えられる以下のいずれもA:\B\C\Dになる
var file1 = new File("A:\\B\\", "C\\D");
var file2 = new File("A:\\B", "C\\D");
var file3 = new File("A:\\B", "\\C\\D");
var file4 = new File("A:\\B\\", "\\C\\D");
var file5 = new File("A:\\B\\\\\\\\", "\\\\\\\\\\C\\D");
String toString()

抽象パス名のパス名文字列を返す

Path toPath()
抽象パスから構築されたjava.nio.file.Pathオブジェクトを返す
File listFiles()
ディレクトリ内のファイルおよびディレクトリを示す抽象パス名
String list()
ディレクトリにあるファイルおよびディレクトリを示す※文字列の配列 ※現在のインスタンスのパス名は不随しない。
boolean exists()
ファイルが存在するか

Pathインタフェース(java.nio.file)

ファイルシステム内のパスをプログラムで表現したもので、ファイルを特定するために使用可能なオブジェクト
特別な区切り文字で区切られた一連のディレクトリ名およびファイル名の要素(名前要素)で構成される階層構造を持つ
Fileクラスで可能な操作は基本的にPathインタフェースでも可能
コンストラク
インタフェース、インスタンス化は以下のいずれかで行う
FileSystems.getDefault().getPath(String first, String... more)
Paths.get(Uri uri)
Paths.get(String first, String... more)
Fileクラスと大きく異なる点は、A:\B:\のような不正なパス(空文字はOK)はInvalidPathExceptionが発生
ただし、WindowsPathParserのエラーなのでOSが異なる場合は不明
Fileクラスと異なり可変長引数で、各引数の結合時の区切り文字はFileクラスと同様

Filesクラス(java.nio.file)

Fileクラスよりも高度なファイル操作を行える。staticメソッドだけで構成されているクラス

【C++】プリコンパイル済みヘッダ

ライブラリ作成時にエラー

ライブラリを作成中に以下のコンパイルエラーが発生した。 C1010:プリコンパイルヘッダーを検索中に不明なEOFが見つかりました。'#include pch.h'をソースに追加しましたか?

 

ttkcd.hatenablog.com

 

pch.h

プリコンパイル済みヘッダ
同じヘッダファイルを複数のソースファイルにインクルードすると、そのたびにヘッダファイルを解析してしまう。
そこで、あらかじめコンパイル(プリコンパイル)したヘッダファイルを用意し、インクルードでは、そのデータを利用する。
プリコンパイル済みヘッダにインクルードするヘッダファイルはiostreamなど、滅多に変更しないヘッダファイルが多い。

解決法

Visual Studio 2017以降で、「ダイナミックリンクライブラリ」、「スタティックライブラリ」のプロジェクトを作成するとデフォルトで作成される。
このため、そのファイルをそのまま使用するか、もしくは以下のようにして無効化する。
[構成のプロパティ]-[C/C++]-[プリコンパイル済みヘッダー]を「プリコンパイル済みヘッダーを使用しない」に設定