- 投稿日:2022-02-01T20:03:51+09:00
MAUIをチュートリアルにしたがって動かしたいのにAndroid Emulatorが動かないときの解決策
MAUIをチュートリアルにしたがって動かしたいのにAndroid Emulatorが動かないときの解決策 自分の環境で起きたことなので、他の人の参考になるかわかりませんが残しておきます。 結論から話しておきますと、PCを再起動・VisualStudioを再起動してみると良いかもしれません。 それでも詰まった場合は、自分のやったことがもしかしたら有効に働いたかもしれませんので読み進めてみてください。 自分の環境で発生した現象 以下のページのリンク先の直前まで実行する。 上記のページではウインドウを閉じると、次のステップである 12.Visual Studio ツールバーで、ピクセル 5-api 30 (Android 11.0-api 30)ボタンを押して、アプリをビルドして実行します。 というように指示されるが、そもそもウインドウを閉じただけではピクセル 5-api 30 (Android 11.0-api 30)ボタンが表示されない。 しょうがなく[Android デバイス マネージャー]ウインドウから対象のエミュレータを実行するものの、以下のようなエラーが発生する。 デバイス エラー: Could not get emulator name after starting AVD pixel_5_-_api_30 トラブルシューティング 手順になかったこととして、以下のダイアログが表示されていた。 "Hyper-V" 機能をオンにして、ネイティブ ハイパーバイザーに切り替え、エミュレーターを加速させてください。 もしかしたら上記の原因があるかもしれないため、一旦[ドキュメント]ボタンを押下してHyper-V機能のOnを試みる。 以下のリンクでは、ファームウェアで仮想化を有効化する方法が書かれています。 その後の手順で、プログラムの有効化のところでHome EditionではHyper-Vが起動できないことに気づいたのですが、とりあえずそれっぽいフォルダのところにチェックを入れました。 すると、再起動が求められたため、PCを再起動してもう一回 VisualStudio2022 を起動しなおすと、ピクセル 5-api 30 (Android 11.0-api 30)ボタンが表示されているため実行してみると… なぜか、動いてる。(本当になんで?) まとめ 結局、何が有効に効いたかわかりませんでした。 プレビュー版ですので、色々とバグがひそんでいるかもしれません。 何か詰まったりしたら、参考にしてみてください。
- 投稿日:2022-02-01T19:20:36+09:00
ExcelVBA使いが、ClosedXMLを利用してみた
はじめに ExcelVBAはよく使っていたんですが、いかんせんレガシーだろうということで、ClosedXML+C#でいろいろやってみたので、そのメモ。 前提など ClosedXMLは[こちら]より取得。 ClosedXML操作サンプル ブックの読み込み・作成・保存 //新たなブックを作成 var workBook = new XLWorkbook(); //既存のブックを開く var workBook2 = new XLWorkbook("C:\\work\\text.xlsx"); //ブックを保存する workBook.SaveAs("C:\\work\\text3.xlsx"); 注意点として、保存するときは、「new XLWorkbook()」するだけではだめで、シートがひとつでもないとエラーになるようです。 ワークシートの読み込み・作成 var workBook = new XLWorkbook(); //既存ワークシートを取得 var workSheet = workBook.Worksheet("sheet1"); //新たなワークシートを追加 var workSheet2 = workBook.Worksheets.Add("sheet2"); セルの参照など var workBook = new XLWorkbook(); var workSheet = workBook.Worksheet("sheet1"); //sheet1のセルA1から値を取得します var cellItem = workSheet.Cell(1, 1).Value; //同様にRange指定で取得します var cellItem2 = workSheet.Ragne("A1").Value; //値の取得には種々のメソッドが用意されているようです var cellStr = workSheet.Cell(1, 1).GetString(); var cellInt = workSheet.Cell(1, 1).GetValue<int>(); Cell、Rangeの扱いはVBAなんかと同じですね。Range(Cell(1,1),Cell(2,2)) みたいな使い方もできるようです。 ちなみに、Valueで取得すると、object形式となるようで、対象のセルに設定される値が決まっている場合は、型指定して取得したほうが安全で扱いやすいかもしれません。 文字列検索、セルのアドレス・行列番号取得 var workBook = new XLWorkbook(); var workSheet = workBook.Worksheet("sheet1"); //シート内を文字列検索します var resultCells = workSheet.Search("hoge"); foreach (var resultCell in resultCells) { //該当セルのアドレスを返却 Console.WriteLine(resultCell.Address); //該当セルの行番号を返却 Console.WriteLine(resultCell.Address.RowNumber); //該当セルの列番号を返却 Console.WriteLine(resultCell.Address.ColumnNumber); } Searchメソッドで文字列を検索し、結果が配列で帰ってきます。Linqも使えるので以下のような方法も可能。AddressメソッドでCell番地情報を取得します。 var resultCell = workSheet.Search("hoge").LastOrDefault().Address.RowNumber シート内で入力されているセルから最終行・列を取得 var workBook = new XLWorkbook(); var workSheet = workBook.Worksheet("sheet1"); //最終行を取得 var lastRow = workSheet.LastRowUsed().RowNumber(); //最終列を取得 var lastCol = workSheet.LastColumnUsed().ColumnNumber(); VBAだと、「.End(xlDown)」とかで取得してたやつに近いかもしれないです。ループ処理で制御するために使うことになりそうです。 シート内から範囲をテーブル形式で取得 var workBook = new XLWorkbook(); var workSheet = workBook.Worksheet("sheet1"); //値が入力されている範囲をテーブル形式で取得 var tbl = workSheet.RangeUsed().AsTable(); //取得結果を行単位でループ foreach(var rowData in tbl.Rows()) { //列単位でループ foreach(var cellData in rowData.Cells()) { Console.WriteLine(cellData.Address); Console.WriteLine(cellData.Value); } } AsTableメソッドでテーブルイメージで一気に値を取得できます。そのあとは行列をループ制御したり、直接セルにアクセスしたりもできるようです。一回でまとめて情報を取得できるので、処理スピードが速くなるかもしれないです。 ちなみに、以下のように範囲を指定して取得することもできます。 var tbl = workSheet2.Range("A1:B3").AsTable(); 使いこなすとかなり便利かもしれないです。 おわり
- 投稿日:2022-02-01T18:36:06+09:00
Unity Edtitorでコンポーネントを一括操作
初めに ヒエラルキーのコンポーネントを一括で操作したい いつも通り、まずはgoogle先生にそれっぽい事の検索から ありました。 とても良いプログラムです。 ですが、今回やりたかったことは、削除だけでなく 各コンポーネントのチェックボックスを外したり、付けたりしたいので ちょっと改造が必要がありました。 ソースを元に色々アレンジ 元のソースはゲームオブジェクトにスクリプトつけて、実行するタイプだったのですが、 メニューから起動できるようにして、削除するだけでなく各コンポーネントのチェックボックスを付けたり 外したりできるようにしました。 using UnityEngine; using UnityEditor; using System.Collections.Generic; public class OperationComponentInChild : EditorWindow { public enum Operation { Enabled, Disabled, Delete, }; private GameObject _objGameObj = null; private Operation _operation = Operation.Enabled; //private string componentName = ""; private List<string> _componentName = new List<string>(); private int _componentIndex = 0; [MenuItem("tool/OperationComponentInChild")] static private void Show() { GetWindow<OperationComponentInChild>(); } /// <summary> /// コンポーネントを探す /// </summary> private void SearchComponent() { _componentIndex = 0; _componentName.Clear(); _componentName.Add("ALL"); var components = _objGameObj.GetComponentsInChildren<UnityEngine.Component>(); foreach (var component in components) { if (component == null) continue; if (component.GetType() != typeof(Transform)) { _componentName.Add(component.GetType().Name); } } } private void OnGUI() { // 自身のSerializedObjectを取得 var so = new SerializedObject(this); EditorGUI.BeginChangeCheck(); _objGameObj = EditorGUILayout.ObjectField("RootGameObj", _objGameObj, typeof(GameObject), true) as GameObject; if (EditorGUI.EndChangeCheck() && _objGameObj) { SearchComponent(); } if (_objGameObj) { EditorGUILayout.Space(); _operation = (Operation)EditorGUILayout.EnumPopup("Operation", _operation); EditorGUILayout.Space(); _componentIndex = EditorGUILayout.Popup("操作したいコンポーネント", _componentIndex, _componentName.ToArray()); //コンポーネントを名前入力するのでなくてあらかじめ調べて、セレクタで出すようにした //EditorGUILayout.LabelField("操作したいコンポーネントを文字列で指定 *[指定なしで全操作]", EditorStyles.boldLabel); //componentName = EditorGUILayout.TextField("ComponentName", componentName); EditorGUILayout.Space(); if (GUILayout.Button("Operation Set")) { var executionFlag = true; if (_operation == Operation.Delete) { if (!EditorUtility.DisplayDialog("確認", "コンポーネントを削除していいですか?", "Yes", "No")) { executionFlag = false; } } if (executionFlag) { GetComAndDes(); } } } so.Update(); so.ApplyModifiedProperties(); } /// <summary> /// コンポーネントを取得して該当コンポーネントを操作 /// </summary> private void GetComAndDes() { var components = _objGameObj.GetComponentsInChildren<UnityEngine.Component>(); foreach (var component in components) { if (component == null) continue; // if (component.GetType().Name == _componentName[_componentIndex] || _componentIndex == 0) { if (component.GetType() != typeof(Transform)) { Debug.Log($"{_operation.ToString()} Operation name {component.gameObject.name} component {component.GetType().Name} "); switch (_operation) { // true case Operation.Enabled: SetComponentObj(component, true); break; // false case Operation.Disabled: SetComponentObj(component, false); break; //削除 case Operation.Delete: DestroyImmediate(component); break; } } } } } /// <summary> /// オブジェクトの操作 /// </summary> /// <param name="comp"></param> /// <param name="flag"></param> private void SetComponentObj(Component comp, bool flag ) { var be = (comp is Behaviour ? (Behaviour)comp : null); var re = (comp is Renderer ? (Renderer)comp : null); var coll = (comp is Collider ? (Collider)comp : null); if (be != null) { be.enabled = flag; } else if (re != null) { re.enabled = flag; } else if (coll != null) { coll.enabled = flag; } else { Debug.Log($"none : {comp.GetType()}"); } } } こんな画面に Selectで選んだり 一応削除する時は確認も出ます。 色々苦労したところ チェックボックスだけを外すのにがてこずった。。 var components = _objGameObj.GetComponentsInChildren<UnityEngine.Component>(); でComponentには、チェックボックスを外すenabledフラグを外す変数がない。。 各コンポーネントはComponentクラスを継承したクラスがそれぞれ用意している var be = (comp is Behaviour ? (Behaviour)comp : null); var re = (comp is Renderer ? (Renderer)comp : null); var coll = (comp is Collider ? (Collider)comp : null); コンポーネントが含まれているかチェックして含まれているならキャストして それぞれのコンポーネントクラスのenabled変数を操作するようにしました。 最後に もっといい方法ないのかな。。 キャストして操作するのちょっと手間と言うか一気に出来たらいいのですが。。。 どなたか教えてください。。。 修正 名前を指定してコンポーネントを操作していたけど、オブジェクトした際に 調べて、セレクタで指定するようにしました。(2022/02/03)
- 投稿日:2022-02-01T18:36:06+09:00
Unity Edtitorコンポーネントを一括操作
初めに ヒエラルキーのコンポーネントを一括で操作したい いつも通り、まずはgoogle先生にそれっぽい事の検索から ありました。 とても良いプログラムです。 ですが、今回やりたかったことは、削除だけでなく 各コンポーネントのチェックボックスを外したり、付けたりしたいので ちょっと改造が必要がありました。 ソースを元に色々アレンジ 元のソースはゲームオブジェクトにスクリプトつけて、実行するタイプだったのですが、 メニューから起動できるようにして、削除するだけでなく各コンポーネントのチェックボックスを付けたり 外したりできるようにしました。 using UnityEngine; using UnityEditor; public class OperationComponentInChild : EditorWindow { public enum Operation { Enabled, Disabled, Delete, }; private GameObject _objGameObj = null; private Operation _operation = Operation.Enabled; private string componentName = ""; [MenuItem("Tools/ShowLog")] static private void Show() { GetWindow<OperationComponentInChild>(); } private void OnGUI() { // 自身のSerializedObjectを取得 var so = new SerializedObject(this); _objGameObj = EditorGUILayout.ObjectField("RootGameObj", _objGameObj, typeof(GameObject), true) as GameObject; if (_objGameObj) { EditorGUILayout.Space(); _operation = (Operation)EditorGUILayout.EnumPopup("Operation", _operation); EditorGUILayout.Space(); EditorGUILayout.LabelField("操作したいコンポーネントを文字列で指定 *[指定なしで全操作]", EditorStyles.boldLabel); componentName = EditorGUILayout.TextField("ComponentName", componentName); EditorGUILayout.Space(); if (GUILayout.Button("Operation Set")) { var executionFlag = true; if (_operation == Operation.Delete) { if (!EditorUtility.DisplayDialog("確認", "コンポーネントを削除していいですか?", "Yes", "No")) { executionFlag = false; } } if (executionFlag) { GetComAndDes(); } } } so.Update(); so.ApplyModifiedProperties(); } /// <summary> /// コンポーネントを取得して該当コンポーネントを操作 /// </summary> private void GetComAndDes() { var components = _objGameObj.GetComponentsInChildren<UnityEngine.Component>(); foreach (var component in components) { if (component == null) continue; // if (component.GetType().Name == componentName || componentName == "") { if (component.GetType() != typeof(Transform)) { Debug.Log($"{_operation.ToString()} Operation name {component.gameObject.name} component {component.GetType().Name} "); switch (_operation) { // true case Operation.Enabled: SetComponentObj(component, true); break; // false case Operation.Disabled: SetComponentObj(component, false); break; //削除 case Operation.Delete: DestroyImmediate(component); break; } } } } } /// <summary> /// オブジェクトの操作 /// </summary> /// <param name="comp"></param> /// <param name="flag"></param> private void SetComponentObj(Component comp, bool flag ) { var be = (comp is Behaviour ? (Behaviour)comp : null); var re = (comp is Renderer ? (Renderer)comp : null); var coll = (comp is Collider ? (Collider)comp : null); if (be != null) { be.enabled = flag; } else if (re != null) { re.enabled = flag; } else if (coll != null) { coll.enabled = flag; } else { Debug.Log($"none : {comp.GetType()}"); } } } こんな画面に Selectで選んだり 一応削除する時は確認も出ます。 色々苦労したところ チェックボックスだけを外すのにがてこずった。。 var components = _objGameObj.GetComponentsInChildren<UnityEngine.Component>(); でComponentには、チェックボックスを外すenabledフラグを外す変数がない。。 各コンポーネントはComponentクラスを継承したクラスがそれぞれ用意している var be = (comp is Behaviour ? (Behaviour)comp : null); var re = (comp is Renderer ? (Renderer)comp : null); var coll = (comp is Collider ? (Collider)comp : null); コンポーネントが含まれているかチェックして含まれているならキャストして それぞれのコンポーネントクラスのenabled変数を操作するようにしました。 最後に もっといい方法ないのかな。。 キャストして操作するのちょっと手間と言うか一気に出来たらいいのですが。。。 どなたか教えてください。。。
- 投稿日:2022-02-01T16:35:13+09:00
C#のコンソールでWinRTのメソッドを試したが動かなかった。
はじめに いきなりC#でUWP(Universal Windows Plaform)を使ってアプリの作成は知識がなく敷居が高いと考えコンソールアプリで始めることを考えました。 そこでネットで例題を探しましたが、参照でWinRT(UWPアプリのためのライブラリ)を 追加しないと動作しない仕様で作られていました。 結局理解しないと進まないようになっていました。 Visual StudioなしでcscだけでWinRTを参照するアプリを作成する方法を 参考ページを見てこれはいい方法を見つけたと考えたのでコードを実装しました。 環境 Windows 11 Pro Visual Studio 2017 Express Windows 10 SDK 作成 Microsoft.Windows.SDK.Contractsの導入 調査したところ、WinRTの機能を利用するために最初NuGetでMicrosoft.Windows.SDK.Contractsを 導入する必要があります。 nuget Microsoft.Windows.SDK.Contracts これでインストールしました。 参考ページを見てcompile.batを作成し、自分で考えたテキストを読む簡単なコードを作成し、コンパイルしてみましたが、途中でエラーになりました。 // using System; using System.IO; using Windows.Graphics.Imaging; using System.Runtime.CompilerServices; using System.Threading.Tasks; using Windows.Storage; using Windows.Foundation; class WinRTTest { [System.STAThread] static void Main(string[] args) { callprocess(); } static async void callprocess() { var path = "test.txt"; var input = await StorageFile.GetFileFromPathAsync(path); } } Task/await/asyncの概念を理解していないので後で調べます。 最初は省略して作成しようとしましたが、 コンパイルエラーになるのでasyncのみ実装しました。 結果 動きませんでした。UWPの概念を理解していない人がコンソールから都合よくUWPの機能だけ利用するのは簡単にはできませんでした。 myexample.cs(22,15): error CS4028: 'await' は、型 'Windows.Foundation.IAsyncOperation<Windows.Storage.StorageFile>' に適切な GetAwaiter メソッドが含まれることを求めています。'System' の using ディレクティブが不足していませんか? 追記 先に進まなくなったのでインタラクティブ環境で動作確認しました。こちらでは動作しました。 Developer Command Prompt VS for 2017からcsiで起動します。 ********************************************************************** ** Visual Studio 2017 Developer Command Prompt v15.9.42 ** Copyright (c) 2017 Microsoft Corporation ********************************************************************** C:\Program Files (x86)\Microsoft Visual Studio\2017\WDExpress>csi Microsoft (R) Visual C# インタラクティブ コンパイラ バージョン 2.10.0.0 Copyright (C) Microsoft Corporation. All rights reserved. 詳細については、「#help」と入力します。 > #r "System.Runtime.WindowsRuntime" > #r "C:\Program Files (x86)\Windows Kits\10\References\10.0.19041.0\Windows.Foundation.UniversalApiContract\10.0.0.0\Windows.Foundation.UniversalApiContract.winmd" > #r "C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.19041.0\Facade\windows.winmd" > #r "C:\Program Files (x86)\Windows Kits\10\References\10.0.19041.0\Windows.Foundation.FoundationContract\4.0.0.0\Windows.Foundation.FoundationContract.winmd" > var result = Windows.Storage.StorageFile.GetFileFromPathAsync(@"C:\users\user\documents\test.txt"); > var file = await result; > string text = await Windows.Storage.FileIO.ReadTextAsync(file); > text "hello" 参考
- 投稿日:2022-02-01T16:35:13+09:00
C#のコンソールでMicrosoft OCRを試した。
はじめに 手軽にOCRができないかということで、 有名なOCRとしてGoogleのTessaract OCRが ありますが、Windowsには標準でMicrosoft OCRが 付属していますのでこちらを利用してみます。 環境 Windows 11 Pro Visual Studio 2017 Express Windows 10 SDK 作成 いきなりC#でUWP(Universal Windows Plaform)を使ってアプリの作成は知識がなく敷居が高いと考えコンソールアプリで始めることを考えました。 そこでネットで例題を探しましたが、参照でWinRT(UWPアプリのためのライブラリ)を 追加しないと動作しない仕様で作られていました。 結局理解しないと進まないようになっていました。 Visual Studioなしでcscだけで作成する方法を 参考ページを見てこれはいい方法を見つけたと考えたので参照しながらコードを実装しました。 Microsoft.Windows.SDK.Contractsの導入 調査したところ、最初NuGetでMicrosoft.Windows.SDK.Contractsを 導入する必要があります。 nuget Microsoft.Windows.SDK.Contracts これでインストールしました。 画面を文字認識(OCR)してみよう!の内容で compile.batを作成し、自分で考えたコードでコンパイルしてみましたが、 途中でエラーになりました。 Task/await/asyncの概念を理解していないので後で調べます。 最初は省略して作成しようとしましたが、 コンパイルエラーになるのでasyncのみ実装しました。 結果 動きませんでした。後で原因を調べます。 error CS0103: 名前 'AsRandomAccessStream' は現在のコンテキスト内に存在しません。 参考
- 投稿日:2022-02-01T16:35:13+09:00
C#のコンソールでMicrosoft OCRを試したが動かなかった。
はじめに 手軽にOCRができないかということで、 有名なOCRとしてGoogleのTessaract OCRが ありますが、Windowsには標準でMicrosoft OCRが 付属していますのでこちらを利用してみます。 環境 Windows 11 Pro Visual Studio 2017 Express Windows 10 SDK 作成 いきなりC#でUWP(Universal Windows Plaform)を使ってアプリの作成は知識がなく敷居が高いと考えコンソールアプリで始めることを考えました。 そこでネットで例題を探しましたが、参照でWinRT(UWPアプリのためのライブラリ)を 追加しないと動作しない仕様で作られていました。 結局理解しないと進まないようになっていました。 Visual Studioなしでcscだけで作成する方法を 参考ページを見てこれはいい方法を見つけたと考えたので参照しながらコードを実装しました。 Microsoft.Windows.SDK.Contractsの導入 調査したところ、最初NuGetでMicrosoft.Windows.SDK.Contractsを 導入する必要があります。 nuget Microsoft.Windows.SDK.Contracts これでインストールしました。 画面を文字認識(OCR)してみよう!の内容で compile.batを作成し、自分で考えたコードでコンパイルしてみましたが、 途中でエラーになりました。 Task/await/asyncの概念を理解していないので後で調べます。 最初は省略して作成しようとしましたが、 コンパイルエラーになるのでasyncのみ実装しました。 結果 動きませんでした。UWPの概念を理解していない人がコンソールから都合よくUWPの機能だけ利用するのは簡単にはできませんでした。 error CS0103: 名前 'AsRandomAccessStream' は現在のコンテキスト内に存在しません。 参考
- 投稿日:2022-02-01T03:16:34+09:00
【C#, WinForms】.NET 5.0 時代の構成ファイル
はじめに C# デスクトップアプリにて、外部ファイルから構成を読み込みたい 構成:データベースへの接続文字列だとか、何らかの機能の初期値など (ASP.NETでは、appsettings.jsonを使うらしい) JSONファイルが登場する以前からある方法として、INIファイルを使う方法がある (参考:2003年に書かれた atmarkIT の記事) .NET Framework から .NET Core を経て、.NET5(現在) となった今、もっとモダンな方法がないか調べて実際に試してみた 試したときの状況 Microsoft Visual Studio Community 2022 (64 ビット) - Preview Version 17.1.0 Preview 3.0 Windows フォームアプリ .NET 5.0(現在) INIファイルを使って構成を読み込む方法 これまで自分が使ってきた方法のおさらい DLLImport 先述の記事の方法 謎のおまじない[DllImport("KERNEL32.DLL")]が書かれたユーティリティクラスを用意して使う ini-parser NuGetからプロジェクトにインストールできる README.mdを読めばすぐに使える、扱いやすいライブラリ しかし、2017年が最終リリースのため、.NET Core 以降に対応しておらず・・・ 互換性がないと表示されるエラーメッセージ パッケージ 'ini-parser 2.5.2' はプロジェクトのターゲット フレームワーク '.NETStandard,Version=v2.1' ではなく '.NETFramework,Version=v4.6.1, .NETFramework,Version=v4.6.2, .NETFramework,Version=v4.7, .NETFramework,Version=v4.7.1, .NETFramework,Version=v4.7.2, .NETFramework,Version=v4.8' を使用して復元されました。このパッケージは、使用しているプロジェクトとの完全な互換性がない可能性があります。 【本題】モダンな方法 MS公式ドキュメントにINI ファイル、JSON ファイル、XML ファイルなどに応じた方法が書かれている INIファイルについて詳細に書かれているページはこちら 構成ファイルの利点について、わかりやすく書かれている 構成ファイルを利用すると、実行時に読み取られアプリケーションの動作に影響を与える、一連のプロパティを格納できます。たとえば、データベースを配置する場所や、ループを実行する回数などです。 この手法の利点は、コードの書き直しや再コンパイルを行わずに、アプリケーションの一部の側面を変更できることです。 そしてモダンな方法への切り替えを推奨している .NET の世界に machine.config ファイルはありません。 また、旧式の System.Configuration 名前空間を使用し続けることもできますが、多くの拡張機能を備えたモダンな Microsoft.Extensions.Configuration に切り替えることを検討してください。 モダンな方法を実際に試してみる 実際にプロジェクトを作成し、順を追ってMicrosoft.Extensions.Configurationを使った方法を試す なお、すでに試されている記事もある(Qiita)(参考にさせていただきました)。 プロジェクトを作成する .NET 5 フォームアプリのプロジェクトを作成し、必要なパッケージを NuGet からインストールする パッケージマネージャーコンソール Install-Package Microsoft.Extensions.Configuration.Ini Install-Package Microsoft.Extensions.Configuration.Binder Install-Package Microsoft.Extensions.Logging パッケージ 用途 Configuration.Ini INIファイルから構成を読みこむため Configuration.Binder ConfigurationBinder 拡張メソッドを使用するため Logging 今回あつかう構成ファイル中に"ログレベル"の項目が存在するため INIファイルを用意する こちらの公式Docと同じINIファイルを使う INIファイルを作成したら、exeファイルと同じ階層に配置する (例)WinFormsApp1\bin\Debug\net5.0-windows\appsettings.ini appsettings.ini SecretKey="Secret key value" [TransientFaultHandlingOptions] Enabled=True AutoRetryDelay="00:00:07" [Logging:LogLevel] Default=Information Microsoft=Warning POCOを作成する INIファイルの各セクションに対応したオブジェクトを作成する TransientFaultHandlingOptions.cs public class TransientFaultHandlingOptions { public bool Enabled { get; set; } public TimeSpan AutoRetryDelay { get; set; } } Logging public class Logging { public const string SectionName = "Logging:LogLevel"; public LogLevel Default { get; set; } public LogLevel Microsoft { get; set; } } ルートとなるBindingClassクラス BindingClass public class BindingClass { public string SecretKey { get; set; } public TransientFaultHandlingOptions TransientFaultHandlingOptions { get; set; } public Logging Logging { get; set; } } INIファイルから構成を読み込む INIファイルから構成を読み込んで、コンソール出力する また、変数にバインディングする Program.cs using Microsoft.Extensions.Configuration; using System; using System.Diagnostics; using System.Linq; using System.Windows.Forms; using Microsoft.Extensions.Logging; static void Main() { var builder = new ConfigurationBuilder() .AddIniFile(path: "appsettings.ini"); var configuration = builder.Build(); // コンソール出力する foreach ((string key, string value) in configuration.AsEnumerable().Where(t => t.Value is not null)) { Debug.WriteLine($"{key}={value}"); } // 変数にバインディングする BindingClass bind = configuration.Get<BindingClass>(); Logging logging = configuration.GetSection(Logging.SectionName).Get<Logging>(); } コンソール出力 foreachでキーと値のペアを出力した様子 コンソール出力 TransientFaultHandlingOptions:Enabled=True TransientFaultHandlingOptions:AutoRetryDelay=00:00:07 SecretKey=Secret key value Logging:LogLevel:Microsoft=Warning Logging:LogLevel:Default=Information 変数にバインディング 拡張メソッドをつかってバインディングしたbind変数のLoggingプロパティにはうまくバインディングできていない Logging変数のDefaultとMicrosoftには、デフォルト値のTraceがセットされている 一方でGetSection(Logging.SectionName)により個別で読み込んだlogging変数には、うまくINIファイルの情報が読みこまれている セクション名が[Logging:LogLevel]のように:で区切られていると、うまくバインディングできない INIファイルに構成の変更を書きこ・・・めなかった 指定されたキーの構成値を設定するSet(string key, string value);メソッドを見つけはしたものの、うまく保存できない INIファイルの扱いについて書かれた公式ドキュメントが「保存」に言及していない時点で、書き込むことができない空気は感じていた・・・ GitHub「なぜConfigurationProviderにはセーブ機能がないのか?」 2016年のISSUEより回答を一部引用 Configurationは基本的にApp.config(これも読み取り専用)だよ。もし構成を書き換えたいのであれば、データベースとか使ったほうがいいと思うよ Configuration is basically replacing App.config - which was read-only as well. In my opinion, if you need to write configuration you need some sort of database. ※ そのあとの返信で、App.configは書き換え可能と記載あり: https://stackoverflow.com/questions/11149556/app-config-change-value こちら2018年のISSUE より .NET Core はもはやASP.NETだけのものじゃないのに、保存機能がないのは馬鹿げている・・など書かれている模様 おわりに いずれにせよAPIの設計思想なんてつよつよエンジニアが決めることだから、私は与えられたもので凌ぐのみ 小さなデスクトップアプリをつくるにしても、なんらかのデータベースを使うことが求められているのかもしれない 参考にさせていただいた記事
- 投稿日:2022-02-01T00:22:04+09:00
staticの使い方
staticの使い方について今日初めて知ったので忘備録としてまとめます。 staticとは? 静的メンバーを作成する際に使用する。 staticをしようすることでインスタンス生成のたびにメモリ領域が確保されるのではなく、アプリでただ1つのメモリ領域が確保される。 変数とメソッド両方に使用可能。 静的メンバー 変数やメソッドをインスタンス単位で生成するのではなく、アプリに一つだけ生成したい場合に使用する。 使い方 クラスのインスタンスを生成するのではなく、クラス名にドットを付けて直接呼び出せる。 参考記事 C#初心者のための基礎!staticスタティックの意味と使い方を解説#25