rksoftware

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

テンプレートの C# コードが以前のバージョンでサポートされない

これはあまり問題にならないと思いますが、言われてみれば、入門者とかは結構はまりそうだなと注目した記事です。

簡単に言うと、.NET 6 で作ったプロジェクトはテンプレートの段階で .NET 6 の機能を使っているので、TargetFramework を落とすとエラーになります。

作ってみる

コンソールアプリを作るコマンド

> dotnet new console

.NET 6 で作られたテンプレート

// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");

TargetFramework を .NET 5 などに変えるとエラーになります。

f:id:rksoftware:20210910004218j:plain

.NET 5 で作られたテンプレート

こんな感じでした。

using System;

namespace TestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}

ちなみに古いバージョンの .NET を使いたい場合は次の記事がおすすめ

暗黙的な名前空間機能

先日、.NET 6 のコードでは、これまで書く必要があった using ディレクティブが不要になっていると書きました。

これはこういうことだったらしいです。

簡単に抜粋すると

次の using は書かなくていい、ということになります。

  • System
  • System.Collections.Generic
  • System.IO
  • System.Linq
  • System.Net.Http
  • System.Threading
  • System.Threading.Tasks

  • System.Net.Http.Json

  • Microsoft.AspNetCore.Builder
  • Microsoft.AspNetCore.Hosting
  • Microsoft.AspNetCore.Http
  • Microsoft.AspNetCore.Routing
  • Microsoft.Extensions.Configuration
  • Microsoft.Extensions.DependencyInjection
  • Microsoft.Extensions.Hosting
  • Microsoft.Extensions.Logging

  • Microsoft.Extensions.Configuration

  • Microsoft.Extensions.DependencyInjection
  • Microsoft.Extensions.Hosting
  • Microsoft.Extensions.Logging

よく using System.Linq; のないソースファイルに出会って おおっと となることがありますが、これからは減りそうですね。

とある機能が本当に新機能か確認する

初めて見る機能が、最新環境での新機能か確認したいこと、とてもよくありますよね?
そんな時私がやってしまうのがこれ この記事のような方法で TargetFramework を一つ前のバージョンに設定してみます。

実践

.NET 6 ではエラーが出ていないコードが

f:id:rksoftware:20210907000908j:plain

.NET 5 ではエラーになります。

f:id:rksoftware:20210907000930j:plain

雑に File.OpenHandle メソッドが .NET 6 だと確認できました。

using 不要

詳細はこれから調べたいと思います。

これまでの C#

次のコードはエラーになります。実際にエラーになっていることがわかるよう画像で貼っておきます。
※一部抜粋ではなく全コードです。

f:id:rksoftware:20210905233425j:plain

using System;
using System.Linq;

がないのでエラーになっています。

.NET 6 のプレビューでの C#

エラーとなりません。

f:id:rksoftware:20210905233407j:plain

いいですね。これ。調べます。

TargetFramework を変更する

以前に書いた関連記事。

概要

.csproj ファイルを編集します。
現在の最新プレビュー版の .NET 環境だと作っただけの .csproj ファイルはこんな感じかと思います。

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>

このファイルの <TargetFramework> を変更すれば OK です。例えば .NET 5 向けにしたい場合は

<TargetFramework>net5.0</TargetFramework>

ですね。

おまけ

Visual Studio を使っていれば GUI から設定も可能です。
Visual Studio 21019 と 2022 プレビュー版で GUI が変わっています。

Visual Studio 21019

プロジェクトのプロパティの アプリケーション タブの中の 対象のフレームワーク
f:id:rksoftware:20210905042320j:plain

Visual Studio 2022 プレビュー

プロジェクトのプロパティの アプリケーション > 全般 タブの中の TargetFramework
f:id:rksoftware:20210905042335j:plain

簡単ですね。

Window のシステムメニューをコマンドで表示する

これです。

f:id:rksoftware:20210904062450j:plain

ウィンドウの左上のアイコンをクリックすると出るやつです。
このメニューは Alt + Space キーで表示できます。

まあ、通常はマウスでクリックすればいいのであまり使う機会はないかもしれません。

ウィンドウがどこにいても使える

この方法にはウィンドウがどこにいても使えるというメリットがあります。
例えばウィンドウが画面外に行ってしまったときでも、システムメニューは画面内に表示されるので、移動最大化 が行えます。

ファイルを同時に読んで書いてしてみる

概要

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

以前に読んでみただけの記事はこちら

読むために必要なもの

読むだけであれば handle の取得は

using SafeFileHandle handle = File.OpenHandle("test.txt");

と、ファイル名だけで良かったのですが、書き込みもするとなると引数 access: の指定が必要。

using SafeFileHandle handle = File.OpenHandle("test.txt", access: FileAccess.ReadWrite);

たったそれだけといえばそれだけでできてしまいます。

あとは、ReadAsync メソッドが WriteAsync メソッドですね。

var t2 = RandomAccess.ReadAsync(handle, buffer2, 1);

var t2 = RandomAccess.WriteAsync(handle, buffer2, 1);

こっちは明らかにそれだけでできていいですね。

コード

コード

// OpenHandle で引数 access: の指定が必要
//using SafeFileHandle handle = File.OpenHandle("test.txt");
using SafeFileHandle handle = File.OpenHandle("test.txt", access: FileAccess.ReadWrite);

var bytes1 = new byte[30];
// 書き込むデータを生成
//var bytes2 = new byte[2];
var bytes2 = "abcdefghijklmnopqrstuvwxyz".Select(c => (byte)c).ToArray();
var bytes3 = new byte[30];
var buffer1 = new Memory<byte>(bytes1);
var buffer2 = new Memory<byte>(bytes2);
var buffer3 = new Memory<byte>(bytes3);

var t1 = RandomAccess.ReadAsync(handle, buffer1, 1);
// Read でなく Write というメソッドを使う
//var t2 = RandomAccess.ReadAsync(handle, buffer2, 1);
var t2 = RandomAccess.WriteAsync(handle, buffer2, 1);
var t3 = RandomAccess.ReadAsync(handle, buffer3, 1);
Task.WaitAll(t1.AsTask(), t2.AsTask(), t3.AsTask());

Console.WriteLine(System.Text.Encoding.Default.GetString(bytes1));
Console.WriteLine(System.Text.Encoding.Default.GetString(bytes2));
Console.WriteLine(System.Text.Encoding.Default.GetString(bytes3));

※ 読み込みは 2 つに増やしています。

test.txt ファイル

12345678901234567890123456789012345678901234567890

実行結果

234567890123456789012345678901
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz8901

または

234567890123456789012345678901
abcdefghijklmnopqrstuvwxyz
234567890123456789012345678901

または

abcdefghijklmnopqrstuvwxyz8901
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz8901

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

■ 補足

handle の取得で引数 access: を指定しないと次の例外です。

Unhandled exception. System.AggregateException: One or more errors occurred. (Access to the path '<ファイルのパス>' is denied.)