rksoftware

Visual Studio とか C# とかが好きです

ファイルを同時に読んでみる

概要

冒頭のリンクの中の Reading & Writing Files という項目が気になったので動かしてみました。 新しいファイル読み書きの API ですね。

試しに一つのファイルを並行で 2 処理で読んでみています。

コード

コード

using SafeFileHandle handle = File.OpenHandle("test.txt");
var bytes1 = new byte[3];
var bytes2 = new byte[2];
var buffer1 = new Memory<byte>(bytes1);
var buffer2 = new Memory<byte>(bytes2);
var t1 = RandomAccess.ReadAsync(handle, buffer1, 1);
var t2 = RandomAccess.ReadAsync(handle, buffer2, 1);
Task.WaitAll(t1.AsTask(), t2.AsTask());
Console.WriteLine(System.Text.Encoding.Default.GetString(bytes1));
Console.WriteLine(System.Text.Encoding.Default.GetString(bytes2));

test.txt ファイル

1234567890

実行結果

234
23

計画通り! ちゃんと読めています。コードもシンプルですしいいですね。static メソッドなのもポイントですね。

dotnet コマンドで使われる dotnet のバージョンを指定する

概要

ディレクトリに global.json ファイルを作って設定を書いておくとそのバージョンが使われます。

作り方

コマンドで簡単に作れます。
最後で指定しているバージョンになります。

dotnet new globaljson --sdk-version 5.0.301

注意

指定するバージョンを間違えてインストールされていない(存在しない)バージョンを設定してしまうと、その後 dotnet コマンドがエラーになってしまいます。

Could not execute because the application was not found or a compatible .NET SDK is not installed.

やってしまった場合は、素直に global.json ファイルを削除してしまいましょう。

ファイルの中身

非常にシンプルで、こんな感じです。

{
  "sdk": {
    "version": "5.0.301"
  }
}

実はいらなかった

これ、今回、.NET 6 の新機能を試そうと思って、まずはこれまで ( .NET 5 以前 ) では使えないことを確認したいと思って使ってみたのですが。

error NETSDK1045: 現在の .NET SDK は、ターゲットとする .NET 6.0 をサポートしていません。.NET 5.0 以下をターゲットとす るか、.NET 6.0 をサポートする .NET SDK のバージョンを使用してください。

というエラーでビルドできないだけという事実を突き付けられました。それはそうですよね。結局、.csproj ファイルの TargetFramework を書き換えてためしました。

せっかくなので書き残しておきます。

Maui の WinUI がデバッグできない

この下の方のプロジェクトがデバッグ実行できなくて試行錯誤しています。

f:id:rksoftware:20210824232938j:plain

ネットの海をさまようと以前のバージョンの際に書かれた記事では皆さんデバッグ実行できていたようなので。

ちなみにデバッグはできなくても、Deploy は可能なので Deploy したものをスタートメニューから実行はできます。

Visual Studio でデバッグ実行しようとすると怒られます。

f:id:rksoftware:20210824233010j:plain

ネット検索すると複数のソースで

  • Project Reunion
  • Single-project MSIX Packaging Tools
  • MSIX Packaging tool

をインストールせよ! と書いてあったのでインストールしてみるも状況変わらず。

ダメっぽい

Visual Studio 2022 で Android エミュレーターを起動する

特に何ということもないのですが、気になったので。
まだ、Visual Studio 2022 はプレビュー段階だし触っていない方もいるかもしれないしということで記事に書いておきます。

■ 結論

これまでと、何も変わっていないし、過去を知らなくてもメニューをポチポチすればすぐ見つかります。

起動するエミュレーターは先日 MAUI の環境構築で作ったものです。

■ 起動手順

Visual Studio のメニューの ツール > Android > Android Device Manager...

f:id:rksoftware:20210821013502j:plain

開始

f:id:rksoftware:20210821013517j:plain

怒られました。

f:id:rksoftware:20210821013530j:plain

Hyper-V か構成されていません
"Hyper-V" 機能をオンにして、ネイティブ ハイパーバイザーに切り替え、エミュレーターを加速させてください。

言われるがままに Hyper-V を有効化します。※手順は省略
ちなみに有効化しないでも起動できますが、ずっと黒い画面のままでした。

f:id:rksoftware:20210821013546j:plain

起動しました。
簡単ですね。

MAUI の Preview 7 が出たので環境を作って実行してみた

アナウンスがこちら。

■ 今回私がやったこと

タイトル詐欺で、実は Preview 7 とか全然関係なく、単純に私が時間がとれたので MAUI を動かしてみただけの記事です。

■ 準備

Visual Studio 2022 の Preview 3 を用意します。
.NET 6 の Preview 7を用意します (Visual Studio 2022 Preview 7 をインストールすれば同時にインストールされると思います)。

■ Visual Studio でワークロードで次のものを追加します。

追加しなかった場合にどうなるのかわかりませんが、ドキュメントにしたがって追加してみました。
ワークロードの追加は Visual Studio のメニューの [ Tools > GetTools and features... ] から行えます。

  • .NET によるモバイル開発
  • ユニバーサル Windows プラットフォーム開発
  • C++ によるデスクトップ開発
  • .NET デスクトップ開発
  • ASP.NET と Web 開発

ここでとても時間がかかるので、覚悟してください。私は 1 時間くらい待って、待ちきれなくて放置したので実際にかかった時間はわかりません。

■ MAUI ワークロードをインストール

dotnet コマンドを実行できるものを管理者モードで起動します。
私は Windows Terminal を起動しました。

次のコマンドを実行します。

> dotnet workload install maui

ここでとても時間がかかるので、覚悟してください。私は 1 時間くらい待って、待ちきれなくて放置したので実際にかかった時間はわかりません。

ちなみに管理者モードにしていないと 「 Inadequate permissions to access, please elevate to run this command 」 と怒られます。

■ maui-check をインストール・実行

ここまででも MAUI のプロジェクトを作成することはできますが、どうやらビルドや実行はまだできません。
maui-check というツールをインストールします。

> dotnet tool install -g redth.net.maui.check

不足しているものを検出してくれます。不足しているものがあると

! Attempt to fix? [y/n] (y):

と聞かれるのですべてを信じて y を入力していきます。

今回は、ビルドツールや、Android エミュレーターや iOS や mac 向けの環境を整えてくれたようです。
今風でかっこいいですね。正直最近はやりの別のクロスプラットフォーム開発ツールがこんな感じのがあってうらやましかったヤツです。

■ プロジェクト (ソリューションを作成)

公式ドキュメントを参照すると、Visual Studio 普通にプロジェクトの新規作成で作れそうなのですが、今回私の手元ではその選択肢が生まれませんでした。
変なことはせず、いつものようにコマンドでプロジェクト (ソリューション) 作ります。

> dotnet new maui

こんな感じでソリューションが生まれます。

f:id:rksoftware:20210815132208j:plain

■ 実行

Visual Studio で開いてソリューションエクスプローラーを見るとこんな感じです。昔よりだいぶシンプルですね。

f:id:rksoftware:20210815132227j:plain

で、Visual Studio で開いて実行をしたいのですが、ここが難しい。
実行のターゲットで、最初から選ばれている Local Device を選択すると iTunes をインストールさせられます。そしてその先で、デバイスを探しはじめてそこから進めません。
iOS 実機で実行しようとしていますね。

f:id:rksoftware:20210815132304j:plain
f:id:rksoftware:20210815132320j:plain

で、今回は Android Emulators からエミュレーターを選択 (maui-check で作られているはず) してみました。

見事、実行されました。

f:id:rksoftware:20210815132341j:plain

今回は一旦ここまで。

DataTable で XML を使う

.NET の System.Data.DataTable。みんな大好きですよね?
実はあまり知られていない事実ですが、DataTable は XML を扱えます。

using System.Data;

// 中身を XML ファイルに出力
{
    var dt = new DataTable();
    dt.TableName = "saitama";
    dt.Columns.Add("no");
    dt.Columns.Add("name");
    dt.Rows.Add(new object[] { 1, "せんべい" });
    dt.Rows.Add(new object[] { 2, "ねぎ" });
    dt.WriteXmlSchema("schema.xml");
    dt.WriteXml("data.xml");
}

// XML ファイルから読み込み
{
    var dt = new DataTable();
    dt.ReadXmlSchema("schema.xml");
    dt.ReadXml("data.xml");
    System.Console.WriteLine($"TebleName:{dt.TableName}");
    foreach (var row in dt.AsEnumerable())
    {
        foreach (DataColumn column in dt.Columns)
            System.Console.Write($"{column.ColumnName}:{row[column.ColumnName]} ");
        System.Console.WriteLine();
    }
}

実行結果

コンソール出力

TebleName:saitama
no:1 name:せんべい
no:2 name:ねぎ

schema.xml

<?xml version="1.0" standalone="yes"?>
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
  <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:MainDataTable="saitama" msdata:UseCurrentLocale="true">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="saitama">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="no" type="xs:string" minOccurs="0" />
              <xs:element name="name" type="xs:string" minOccurs="0" />
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>

data.xml

<?xml version="1.0" standalone="yes"?>
<DocumentElement>
  <saitama>
    <no>1</no>
    <name>せんべい</name>
  </saitama>
  <saitama>
    <no>2</no>
    <name>ねぎ</name>
  </saitama>
</DocumentElement>

作り捨てアプリであれば意外に便利に使えたりします。
しかし役に立つ機会はあまりないかもしれないので、誰かに「できる」と言われたときに「できない」と主張してしまわない程度に覚えておきましょう。

.NET で SQLite を使う まとめ

.NET で SQLite を使ってみます。
過去に書いたい着くかの記事のまとめです。

今回の流れ

  • NuGet からパッケージインストール
  • データベースファイルを作って
  • テーブルを作って
  • テーブルの定義を読んで
  • データを Insert して
  • データを Select します

NuGet からパッケージインストール

今回使うライブラリを NuGet からインストールしてください。

  • Microsoft.Data.Sqlite

データベースファイルを作る

データベースファイルはカレントディレクトリに Data Source で指定したファイル名で作成されます。
カレントディレクトリを変更することで、ファイルが作成される場所を変更できます。

例えば次のようにすることで、カレントディレクトリの下の data というディレクトリの中に database.db というファイル名で作成できます。

using (var connection = new SqliteConnection("Data Source=data/database.db"))

テーブルを作る

データベースとして使うためにはまずはテーブルを作らなければなりません。
まあ特別なことはなく、次の一文を実行するだけです。

CREATE TABLE IF NOT EXISTS saitama ( no INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL );

C# 上で実行するコードは次のような感じです。

// テーブルを作成する
command.CommandText = "CREATE TABLE IF NOT EXISTS saitama ( no INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL);";
command.ExecuteNonQuery();

テーブルの定義を読む

アプリの中でテーブルの定義を確認したいことは実は良くあります。
次のような一文を実行します。

PRAGMA TABLE_INFO ('saitama')

C# 上で実行するコードは次のような感じです。

// テーブルの情報を取得/表示してみる
Console.WriteLine("テーブルの情報");
command.CommandText = "PRAGMA TABLE_INFO ('saitama')";
using (var reader = command.ExecuteReader())
{
    var dt = new DataTable();
    dt.Load(reader);
    // 結果を表示
    foreach (var row in dt.AsEnumerable())
    {
        foreach (DataColumn col in dt.Columns)
            Console.Write($"{col.ColumnName}:{row[col.ColumnName]} ");
        Console.WriteLine();
    }
}

データを Insert する

今回、とりあえずデータの Select までをやりたいので、Select するためのデータを Insert します。
Insert ですから特別なことは何もないです。

insert into saitama values (1, 'せんべい');

C# 上で実行するコードは次のような感じです。

// テーブルにデータを Insert する
command.CommandText = "insert into saitama values (1, 'せんべい');";
command.ExecuteNonQuery();

データを Select する

データを Select します。やはり特別なことは何もないです。

select * from saitama where no = $no;

C# 上で実行するコードは次のような感じです。

// テーブルを検索する
command.CommandText = "select * from saitama where no = $no;";
command.Parameters.AddWithValue("$no", 1);
using (var reader = command.ExecuteReader())
{
    var dt = new DataTable();
    dt.Load(reader);
    // 結果を表示
    foreach (var row in dt.AsEnumerable())
        Console.WriteLine($"Saitama, {row["name"]}");
}

全体をつなげて実行できるコードにする

前述の要素たちをつなげて動作する一つのコードにまとめてみます。
もし試す際はこのコードをコピー&ペーストして試してください。
※要素間のつなぎや、複数回実行するときのためのコードで少し書き足しがあります。

using Microsoft.Data.Sqlite;
using System;
using System.Data;
using System.IO;
using System.Linq;

// カレントディレクトリに data というディレクトリを作って database.db という名前でデータベースのファイルを作る
// まずは data ディレクトリをなければ作成
var directory = new DirectoryInfo(Path.Combine(Environment.CurrentDirectory, "data"));
if (!directory.Exists) directory.Create();
// データ Insert 用のサンプルなので、毎回初期化したい。雑にデータベースファイルを毎回作り直してしまうために一旦削除する
var file = new FileInfo(Path.Combine(Environment.CurrentDirectory, "data", "database.db"));
if (file.Exists) file.Delete();

// データベースファイルは data/database.db
using (var connection = new SqliteConnection("Data Source=data/database.db"))
{
    connection.Open();
    var command = connection.CreateCommand();

    // テーブルを作成する
    command.CommandText = "CREATE TABLE IF NOT EXISTS saitama ( no INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL);";
    command.ExecuteNonQuery();

    // 一旦テーブルの情報を取得/表示してみる
    Console.WriteLine("テーブルの情報");
    command.CommandText = "PRAGMA TABLE_INFO ('saitama')";
    using (var reader = command.ExecuteReader())
    {
        var dt = new DataTable();
        dt.Load(reader);

        // 結果を表示
        foreach (var row in dt.AsEnumerable())
        {
            foreach (DataColumn col in dt.Columns)
                Console.Write($"{col.ColumnName}:{row[col.ColumnName]} ");
            Console.WriteLine();
        }
    }

    Console.WriteLine();

    // テーブルにデータを Insert する
    command.CommandText = "insert into saitama values (1, 'せんべい');";
    command.ExecuteNonQuery();

    // テーブルを検索する
    Console.WriteLine("データの検索結果");
    command.CommandText = "select * from saitama where no = $no;";
    command.Parameters.AddWithValue("$no", 1);
    using (var reader = command.ExecuteReader())
    {
        var dt = new DataTable();
        dt.Load(reader);

        // 結果を表示
        foreach (var row in dt.AsEnumerable())
            Console.WriteLine($"Saitama, {row["name"]}");
    }
}

実行結果

テーブルの情報
cid:0 name:no type:INTEGER notnull:1 dflt_value: pk:1
cid:1 name:name type:TEXT notnull:1 dflt_value: pk:0

データの検索結果
Saitama, せんべい

簡単ですね。

以前に書いた個々の要素

今回よりもう少し詳しく書いています。