- 投稿日:2019-10-24T22:24:43+09:00
COMオブジェクトの解放のお作法 - C#(というか.NET)
経緯
COM Objectといえば「
ReleaseComObject
で解放だー」みたいな印象があるが、.NETからExcelとか操作してると、いろんなオブジェクトが参照カウント増やしてくれやがるので、管理できなくなるしtry{...}finally{解放処理}
のネストがエグくなる。そんななか
Marshal.ReleaseComObject
は危険な場合があるというのを目にして、どうやればよいのか、
COMオブジェクト×.NETに関するKindle書籍(下記「参考書籍」参照)を持ってたので少し調べてみた。参考書籍
.NET and COM: The Complete Interoperability Guide - Adam Nathan著
著者はMicrosoftの中の人のよう。
読破できる気がしないので、書籍内検索する形で活用。
GCに任せる方法
6章Advanced Topics for Using COM Components の Listing 6.5 とその前のあたりの記載より。
GCに任せるという手法が紹介されている。(推奨なのかどうかは読解できず。)
(まんま載せると著作権的によくなさそうなので雰囲気だけ。)
using System.Runtime.CompilerServices; [MethodImpl(MethodImplOptions.NoInlining)] static void WorkWithMsOfficeComponent() { XXX(Excelとか).Application app = new XXX.Application(); ... app.Quit(); } static void Main() { WorkWithMsOfficeComponent(); GC.Collect(); GC.WaitForPendingFinalizers(); }スコープ(変数の生存区間)の短いauto変数に押し込めることができるなら、上記のやりかたが楽っぽい。
属性
[MethodImpl(MethodImplOptions.NoInlining)]
を指定しているのは、JIT1によるインライン展開を防止してGCを意図通りに機能させるため。参考サイト
計測方法とかが参考になりそう。(時間なくてまだ試せていないです。)
.NETを使ったOfficeの自動化が面倒なはずがない―そう考えていた時期が俺にもありました。
JIT(Just in time)コンパイラ(実行時にNativeな実行プログラムにコンパイルされる)によってインライン展開されると、変数の生存区間がプログラマの意図通りにならず、結果としてGCがプログラマの意図通りに動作しない。 ↩
- 投稿日:2019-10-24T21:50:19+09:00
ASP.NET Core 3.0 Razor Pages 事始め(2)
前回:ASP.NET Core 3.0 Razor Pages 事始め(1) の続きです。
今日はモデル(映画を管理するクラス)を追加し、新規追加、編集、削除、一覧のページを作成します。
モデルの追加
まず、VS Codeのエクスプローラーの RAZORPAGEMOVIE を選択後、 [新しいフォルダー] アイコンをクリックし、Models フォルダーを作成します。
Modelsフォルダ を右クリックし、[新しいファイル] で、Movie.csを作成します。
Movie
クラスを以下のように定義します。using System; using System.ComponentModel.DataAnnotations; namespace RazorPagesMovie.Models { public class Movie { public int ID { get; set; } public string Title { get; set; } [DataType(DataType.Date)] public DateTime ReleaseDate { get; set; } public string Genre { get; set; } public decimal Price { get; set; } } }Movieクラスには、IDというプロパティがあります。これがデータベースのテーブルの主キーになります。
ReleaseDate
プロパティには、[DataType(DataType.Date)]
という属性が付加されています。これは、時刻の情報は利用しないという意味です。
UI側では、日付のみの入力、表示となります。Ctrl+Shift+Bで プロジェクトをビルドして、エラーがないことを確認します。
Movie モデルの追加
RazorPagesMovie プロジェクトの下に、Data フォルダを作成します。
RazorPagesMovieContext.cs ファイルを作成し、以下のように入力します。
using Microsoft.EntityFrameworkCore; namespace RazorPagesMovie.Data { public class RazorPagesMovieContext : DbContext { public RazorPagesMovieContext (DbContextOptions<RazorPagesMovieContext> options) : base(options) { } public DbSet<RazorPagesMovie.Models.Movie> Movie { get; set; } } }
RazorPagesMovieContext
は、Microsoft.EntityFrameworkCore.DbContext
から派生しています。
Movie
は、エンティティセット(EntityFrameworkの用語)と呼ばれるプロパティで、データベースのテーブルに対応します。接続文字列の追加
次に、
appsettings.json
ファイルに接続文字列を追加します。"ConnectionStrings"
がその指定している個所です。{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*", "ConnectionStrings": { "MovieContext": "Data Source=MvcMovie.db" } }NuGet パッケージと EF ツールの追加
次の コマンドを実行し、各種パッケージをインストールします。
dotnet tool install --global dotnet-ef dotnet add package Microsoft.EntityFrameworkCore.SQLite dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design dotnet add package Microsoft.EntityFrameworkCore.Design dotnet add package Microsoft.EntityFrameworkCore.SqlServerこれで、以下のものが追加されます。
- .NET Core CLI の Entity Framework Core ツール
- EF Core SQLite プロバイダー
- EF のスキャフォールディングに必要なパッケージ
データベース コンテキストの登録
Startup.cs の
ConfigureServices
メソッドの最後に、services.AddDbContext
の呼び出しを追加します。using RazorPagesMovie.Data; using Microsoft.EntityFrameworkCore; … public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); services.AddDbContext<RazorPagesMovieContext>(options => options.UseSqlite(Configuration.GetConnectionString("MovieContext"))); }プロジェクトをビルドして、コンパイル エラーがないことを確認します。
Prgoram.cs を覗いてみる
ところで、このStartUp.csに定義されている
Startup
クラスは、どこで参照しているのでしょうか? 調べたところ、Program.csで参照していました。Program.csは、以下のようなコードになっています。
using System; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.DependencyInjection; namespace RazorPagesMovie { public class Program { public static void Main(string[] args) { CreateWebHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); } }具体的に何をやっているのかまでは、このコードだけから正確には理解はできませんが、ホストと言われるインスタンスを生成し、起動しているようです。そして、ホストを生成する際には、初期処理を行うためのクラスが
Startup
クラスだよと、指定しているということですね。何か特別の初期処理をやらせたいという時だけ、この
Program
クラスのコードをいじることになると思われます。ムービーモデルのスキャフォールディング
次に、作成したMovieモデルから、Create, Edit, Delete, Details, Index の各ページを作成します。
まず、以下のコマンドを実行します。
dotnet tool install --global dotnet-aspnet-codegeneratorこれで、aspnet-codegenerator スキャフォールディング ツールがインストールされます。なお、このツールの実行には、先ほどインストールしたパッケージが必要になります。
続けて、次のコマンドを実行し、コードを自動生成します。
dotnet aspnet-codegenerator razorpage -m Movie -dc RazorPagesMovieContext -udl -outDir Pages/Movies --referenceScriptLibraries以下、その実行結果です。
$ dotnet aspnet-codegenerator razorpage -m Movie -dc RazorPagesMovieContext -udl -outDir Pages/Movies Building project ... Finding the generator 'razorpage'... Running the generator 'razorpage'... Attempting to compile the application in memory. Attempting to figure out the EntityFramework metadata for the model and DbContext: 'Movie' info: Microsoft.EntityFrameworkCore.Infrastructure[10403] Entity Framework Core 3.0.0 initialized 'RazorPagesMovieContext' using provider 'Microsoft.EntityFrameworkCore.Sqlite' with options: None Added Razor Page : /Pages/Movies/Create.cshtml Added PageModel : /Pages/Movies/Create.cshtml.cs Added Razor Page : /Pages/Movies/Edit.cshtml Added PageModel : /Pages/Movies/Edit.cshtml.cs Added Razor Page : /Pages/Movies/Details.cshtml Added PageModel : /Pages/Movies/Details.cshtml.cs Added Razor Page : /Pages/Movies/Delete.cshtml Added PageModel : /Pages/Movies/Delete.cshtml.cs Added Razor Page : /Pages/Movies/Index.cshtml Added PageModel : /Pages/Movies/Index.cshtml.cs RunTime 00:00:17.52VSCodeのエクスプローラーを見ると、プロジェクトに新たなフォルダ、ファイルが追加されているのが確認できます。
Pages/Moveisフォルダー Create.cshtml Create.cshtml.cs Delete.cshtml Delete.cshtml.cs Details.cshtml Details.cshtml.cs Edit.cshtml Edit.cshtml.cs Index.cshtml Index.cshtml.cs最初のDBマイグレーション
次の コマンドを実行します。
dotnet ef migrations add InitialCreate dotnet ef database update
ef migrations add InitialCreate
コマンド
ef migrations add InitialCreate
コマンドは、最初のデータベース スキーマを作成するコードをMigrations
フォルダに生成します。InitialCreate という名前は任意です。
このコマンドは、
RazorPagesMovieContext
内の以下のコードをみて、どのようなテーブルを生成したらよいかを判断しています。public DbSet<RazorPagesMovie.Models.Movie> Movie { get; set; }
ef database update
コマンド
ef database update
コマンドは、Migrations
フォルダに作成された<time-stamp>_InitialCreate.cs
ファイルのUp
メソッドを実行します。Up
メソッドにより、データベースが作成されます。
Up
メソッドをここに示します。protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.CreateTable( name: "Movie", columns: table => new { ID = table.Column<int>(nullable: false) .Annotation("Sqlite:Autoincrement", true), Title = table.Column<string>(nullable: true), ReleaseDate = table.Column<DateTime>(nullable: false), Genre = table.Column<string>(nullable: true), Price = table.Column<decimal>(nullable: false) }, constraints: table => { table.PrimaryKey("PK_Movie", x => x.ID); }); }
ef database update
コマンドを実行すると、プロジェクトのあるフォルダに、MvcMovie.db というファイルが作成されているのが確認できます。アプリのテスト
F5キーでアプリを実行後、ブラウザの URLに /movies を追加してenterキーを押します。
これでMovies/index ページが表示されました。
Create, Edit, Deleteのページが動作するかも確認します。
やっと、ここまで来ました。正直、かなり面倒臭いですね。可能ならば、Visual Studio IDE使ったほうがはるかに簡単だと思われます。
次回は、スキャフォールディングで生成されたRazorページについて、見ていこうと思います。
- 投稿日:2019-10-24T20:10:55+09:00
TelloをUnityでC#するTelloLibを使って
UnityでC#してドローン制御したかったのでメモ
TelloのWifiにPCを接続
ノートPCなどですとWifi接続が楽ですね
TelloUnityDemoで楽をする
Gitにサンプルコードあったので、乗っかります
https://github.com/comoc/TelloForUnityTelloLibは後入れなので、下記のものを追加します
https://github.com/comoc/TelloLib.git映像がでないけど色々データ取れた
とりあえず。Windowsのファイアウォールを全部OFFにしたら表示できた。。
Windows Specific Settings Please confirm the Windows Firewall settings of your Unity Editor. Public network access is required to receive the video stream from Tello.って書いてあった。。
https://github.com/comoc/TelloForUnity
に。。TelloをStationModeへ
ほんとはTelloをStationModeにすれば
他のWifiにぶら下がれるので
つぎは、このあたり設定したいです。参考サイト
TelloForUnity
https://github.com/comoc/TelloForUnityTelloLib
https://github.com/Kragrathea/TelloLibTelloLib
https://github.com/comoc/TelloLib.gitUnityでUDPを送信してみる
https://qiita.com/nenjiru/items/d9c4e8a22601deb0425bTello EDUをNode-REDから station mode にして操作するメモ
https://www.1ft-seabass.jp/memo/2019/05/01/tello-edu-meets-nodered-setting-station-mode/
- 投稿日:2019-10-24T18:41:37+09:00
.NET Core 3.0のPublish Single File概要
はじめに
本スライドは「C# Tokyo」ユーザーグループの下記のイベントの発表資料です。
.NET Core 3.0 リリース記念 C# Tokyo 2019/10
.NET Core 3.0の魅力
- 単一実行可能ファイル
- Side by Sideの復活
- 快適な動作速度
- WPF・WinFormsのサポート
- 先進的な機能の数々
本日のお題
- 単一実行可能ファイル
- Runtimeの同梱・非同梱
- AOTコンパイル
何がうれしいのか?
- 配布品質の向上(配布ミス削減)
- 配布先環境のRuntime非依存
- Runtimeの混在が可能
- Runtimeの逐次バージョンアップが容易に
- AOTによる起動速度の向上
注意点
- これがすべてじゃないのが注意点
- でかい
- 初回起動速度の低下(unzip処理が発生)
- でかい
- 実行パスが配置した場所と異なる
- でかい
とはいえ...
- サーバーサイドではメリットが勝ちそう?※
- ランタイム非同梱ならクライアントでも?
導入背景によるので一概にはなんとも
※IISやWindows Serviceへの登録はまだ未確認
具体的なパラメーター
No. 項目 説明 1 /p:PublishSingleFile 単一ファイルの実行可能バイナリの作成 2 /p:PublishReadyToRun AOTコンパイル 3 /p:PublishTrimmed 不要コードの削除 4 Warp 同上(サードパーティ製) 5 --self-contained ランタイム同梱するか否か
Demo
Demo Script
mkdir Demo cd Demo dotnet new sln mkdir ConsoleApp cd ConsoleApp dotnet new console dotnet sln ..\Demo.sln add ConsoleApp.csproj dotnet run dotnet publish -c Release -r win10-x64 dotnet publish -c Release -r win10-x64 /p:PublishSingleFile=true dotnet publish -c Release -r win10-x64 /p:PublishSingleFile=true /p:PublishReadyToRun=true dotnet publish -c Release -r win10-x64 /p:PublishSingleFile=true /p:PublishReadyToRun=true /p:PublishTrimmed=true [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls" ; Invoke-WebRequest https://github.com/dgiagio/warp/releases/download/v0.3.0/windows-x64.warp-packer.exe -OutFile warp-packer.exe .\warp-packer --arch windows-x64 --input_dir bin\Release\netcoreapp3.0\win10-x64\publish --exec ConsoleApp.exe --output ConsoleApp.exe dotnet publish -c Release -r win10-x64 /p:PublishSingleFile=true /p:PublishReadyToRun=true --self-contained=false
空コンソールアプリのファイルサイズ
No. 項目 Case1 Case2 Case2 Case3 Case4 Case5 1 /p:PublishSingleFile - TRUE TRUE TRUE TRUE TRUE 2 /p:PublishReadyToRun - - TRUE TRUE TRUE TRUE 3 /p:PublishTrimmed - - - TRUE TRUE - 4 Warp - - - - TRUE - 5 --self-contained - TRUE TRUE TRUE TRUE FALSE サイズ 161[KB] 65.8 [MB] 65.8 [MB] 25.4 [MB] 12.0[MB] 162 [KB]
空WPFアプリのファイルサイズ
No. 項目 Case1 Case2 Case2 Case3 Case4 Case5 1 /p:PublishSingleFile - TRUE TRUE TRUE TRUE TRUE 2 /p:PublishReadyToRun TRUE TRUE TRUE TRUE 3 /p:PublishTrimmed TRUE TRUE - 4 Warp TRUE - 5 --self-contained TRUE TRUE TRUE TRUE FALSE サイズ 164[KB] 149 [MB] 149 [MB] 134 [MB] 55.5[MB] 164 [KB]
.csprojにも書けます
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp3.0</TargetFramework> <PublishTrimmed>true</PublishTrimmed> <PublishReadyToRun>true</PublishReadyToRun> </PropertyGroup> </Project>参考情報
公式ドキュメント
https://github.com/dotnet/designs/blob/master/accepted/single-file/design.md#user-experienceなぜか詳しいおっちゃんのサイト
https://www.hanselman.com/blog/MakingATinyNETCore30EntirelySelfcontainedSingleExecutable.aspx
完
- 投稿日:2019-10-24T17:55:58+09:00
Error -C# wpf GUIプログラミング
https://qiita.com/Kosen-amai/items/88b3d987b41f46ebea4b
Windows GUIプログラミング入門2 デジタル時計という記事を参考にして、プログラムを書いているのですが、なかなかエラーが解決できずに困っています。
分かったら、この記事を編集して、ほかの人のエラーの助けになればいいと思っています。
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Threading; namespace tutorial02 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { /// <summary> /// 時刻表示用タイマー /// </summary> private DispatcherTimer timer; public MainWindow() { InitializeComponent(); // タイマー生成 timer = CreateTimer(); } /// <summary> /// タイマー生成処理 /// </summary> /// <returns>生成したタイマー</returns> private static DispatcherTimer CreateTimer() { //タイマー生成(湯煎度はアイドル時に設定) var t = new DispatcherTimer(DispatcherPriority.SystemIdle); // タイマーイベントの発生間隔を300ミリ秒に設定 t.Interval = TimeSpan.FromMilliseconds(300); // タイマーイベントの定義 t.Tick += (sender, e) => { //タイマーイベントの発生時の処理をここに書く // 現在の時分秒をテキストに設定 TextBlock.Text = DateTime.Now.ToString("HH:mm:ss"); }; //生成したタイマーを返す return t; } private void TextBlock_MouseDown(object sender, MouseButtonEventArgs e) { // タイマー開始 timer.Start(); } } }エラーメッセージ
- 投稿日:2019-10-24T17:42:15+09:00
C# クラスについて理解できるようにまとめてみた。(猫でも)
C#におけるクラスについて猫でも分かるように解説してみた
まず、用語編と説明編にわけて解説していくので目次のページから用語がわからなくなったら、用語編に戻ってみてくださいませ。
また、筆者がむむと思った用語はすべて用語編に書かれていますので、ご安心を
用語編
クラスとは
クラスとは一般的にものを作る設計図となっています。
オブジェクトとは
クラス(設計図)で作られた成果物のこと
メンバ変数
クラスの中で宣言される変数のこと。
クラスの中でxとかnumとか変数が定義されたら、それはメンバ変数です。
メンバ関数
メンバ関数とは、クラス内で定義される関数(メソッド)のことです。
メソッド
一連の処理をまとめて繰り返し使えるようにした塊のこと。
関数化したものをメソッドという。
関数 = メソッド
using System;
名前空間とも呼ばれます。
さっきからusing System;という文言が出てきているのにも関わらず、あれなんであるのか?となっていませんでしたか?
ごめんなさい。説明が遅れました。
using System;
とはフォルダを参照しているのです。
例えば、
using System; class Sample{ public static void Main(){ Console.WriteLine("hello world!"); } }これでhello world!と出力されます。
もしusing System;がなかったら、
class Sample{ public static void Main(){ System.Console.WriteLine("hello world!"); } }といちいちSystemと書かなければいけないのです。
この面倒を省くために、using System;
と先頭に書き、これからSystemフォルダの中を参照して、様々なメソッドを使いますよ
ということを書いているのです。
コンストラクタ
コンストラクタとはクラスを生成したとき、自動的に実行される初期化用のメソッドです。
継承
あるクラスの機能を受け継いで新しいクラスを作ること
private
外部からアクセス(読み書き)できないように制限する
public
外部からアクセス(読み書き)が自由
static
static とつけると静的メンバーになる
静的メンバーの使い方
クラスのメンバー(フィールドやメソッド)を定義する際に、
static
キーワードを付けることで、 その変数は静的メンバー変数・静的メソッドになります。 例えば、静的フィールドであれば以下のように書きます。static 型名 フィールド名静的メンバーはクラスごとに唯一つの実体を持ち、すべてのインスタンスの間で共有されます。
例として、人間について考えてみましょう。 この場合、特定のインスタンスとは個人個人のこと、 クラスとは人間という種別そのもののことになるわけですが、 名前や年齢などは各個人ごとに異なります。 一方で、人という種の学名「Homo sapiens」などのように個体によらない共通のものもあります。 したがって、人間をあらわす
Person
というクラスを作成した場合、name
(名前)やage
(年齢)といったメンバー変数を作りたい場合はインスタンス フィールドに、scientificName
(学名)などのクラス全体で共有すべき変数を作りたい場合は静的フィールドにすべきです。 (実際には学名などの普遍な値は定数(const
)として定義すべきですが、 ここでは説明のためということでご容赦を。 定数の定義については後ほど説明します。)class Person { public string name; // 名前。個体ごとに違うので、インスタンス フィールドに。 public int age; // 年齢。同上、インスタンス フィールドに。 public static string scientificName; // 学名。個体じゃなくて種によって決まるものなので、静的フィールドに。 }集団で分けるなら、static を使い、個々で分けるならstaticはつけない
void
voidとは戻り値を返さないこと
値を返したくなかったら、voidをつけること
説明編
クラス(設計図)の書き方
クラスの基本的な書き方は以下の通りとなります。
using System; class クラス名{ //クラス名は自分で決めてよい。また、クラス名は大文字から始まる。 //クラスの中を記述する }メンバ変数について
using System; class Sample{ int a = 1; string str = "test"; }このようなSampleクラスがあるとaやintがメンバ変数となります。
メンバ関数について
using System; class Sample{ public static void test1(){ // メソッド内の処理を記述する } }このようにしてtest1()というメソッドを呼び出すことができます。
ここのpublic static void は少し待ってください。
インスタンス
インスタンスとは、クラスを元にした実体のことです。
大体、インスタンス = オブジェクトという認識でOKです。
サンプルコードを見てみましょう
using System; namespace SampleApplication{ class Sample{ // sample クラスを定義 int r; //int r, double cir変数を定義する public void Circle(){ // メンバ関数を定義 double cir = 2 * 3.14 * r; Console.WriteLine("半径:" + r + ", 円周の長さ" + cir); } public static void Main(){ //実行後にこれが実行される(エントリーポイントと もいう) Sample cls = new Sample(); // これでクラス名からインスタンスを生成 //Sampleクラスからclsというインスタンスを生成 cls.r = 4; //clsの中の変数である、rに4を代入 cls.Circle(); // cls.Circle()でclsをCircle()関数のなかで実行 } } }実行結果
半径:4, 円周の長さ:25.12つまり、インスタンスとは、クラス(設計図)からより簡単に実態を作るために書くものである。
書き方としては、
クラス名 変数名; 変数名 = new クラス名();または、
クラス名 変数名 = new クラス名();というようにインスタンス名を生成できる
また、インスタンスからメンバ変数、メンバ関数を利用するためには
変数名.メンバ名と書いて利用できる
コンストラクタについて
cls.r = 4;のように直接、値を代入しました。しかし、実際に値をセットするのはメソッドを使うことが望ましいとされています。
その際に使われるメソッドとして、コンストラクタというメソッドがあります
using System; namespace{ class Sample{ int r //メンバ変数を定義 public Sample(int r){ // これがコンストラクタ // コンストラクタの処理を記述する this.r = r; //引数として渡された値をメンバへ変数rに代入 } public void Circle(){ double cir = 2 * 3.14 * r; COnsole.WriteLine("半径:" + r + ", 円周の長さ" + cir) } public static void Main(){ Sample cls = new Sample(4); //インスタンスを生成する前にコンストラクタへ渡す引数を指定する cls.Circle(); // メンバ関数の呼び出し } } }この際のポイントは、2つあります。
コンストラクタ名は、クラス名と同じにする必要がある。 コンストラクタに引数を渡すときは、インスタンスを生成する際に値を指定する。クラスの継承について
using System namespace SampleApplication1 { class Person //Personクラス { string name; int age; public Person(string name, int age) // コンストラクタを生成 { this.name = name; this.age = age; Console.WriteLine("Personクラスのコンストラクタ"); Console.WriteLine("名前: " + name + ", 年齢: " + age); } } class Employee : Person // Personクラスを継承した、Employeeクラス { int id; string department; public Employee(string name, int age, int id, string department) : base(name, age) { this.id = id; this.department = department; Console.WriteLine("Employeeクラスのコンストラクタ"); Console.WriteLine("社員番号: " + id + "部署: " + department); } public static void Main(){ Employee empl_1 = new Employee("ichiro", 25, 123456, "system"); //インスタンスを生成 } } }上記のコードでは、基本となったものをPersonクラスを基底クラス、継承したものを派生クラスと呼んでいる
以上
参考にさせてもらったサイト
(https://www.sejuku.net/blog/102559)
もう参考にさせてもらったというよりは、このサイトを見て自分なりにわからないところを付け加えた感じです。
自分なりにまとめてみると結構理解できるので、プログラミングノートを書くのは、おすすめです。間違っている個所などございまいたら、お気軽にコメントしていただけたらありがたいです。
- 投稿日:2019-10-24T15:19:32+09:00
Logitech G29 SteeringWheel PCでUnityできるまで
Logitech G29 SteeringWheel PCでUnityできるまで
ハンドルコントローラの動作環境とUnityでサンプル動作のメモ
たぶんドライバーインストール(Win 64bit)
ダウンロード先
https://support.logi.com/hc/ja/articles/360025298053-Logitech-Gaming-Software対象exe
LGS_9.02.65_x64_Logicool.exeSDKダウンロード
Logitech Gaming SDK
https://assetstore.unity.com/packages/tools/integration/logitech-gaming-sdk-6630
UnityでSample起動でエラー
どうやらdllが壊れているらしいかもなので
https://gaming.logicool.co.jp/ja-jp/partnerdeveloperlab/sdk-resource-list/steering-wheel-sdk.html
からダウンロードしたdllで上書きしたら動作した。正常なdll LogitechSteeringWheelSDK_8.75.30\Lib\GameEnginesWrapper\x64 LogitechSteeringWheelEnginesWrapper.dll 上書き対象 Assets\Logitech SDK LogitechSteeringWheelEnginesWrapper.dllUnityでC#でのハンドル接続
キーボードでハンドルの重さ?など変えたりできるみたいです。
オフロード設定でガタガタなりました。参考サイト
ステアリングホイールSDK
https://gaming.logicool.co.jp/ja-jp/partnerdeveloperlab/sdk-resource-list/steering-wheel-sdk.htmlLogitech Gaming SDK
https://assetstore.unity.com/packages/tools/integration/logitech-gaming-sdk-6630Logitech Gaming Software
https://support.logi.com/hc/ja/articles/360025298053-Logitech-Gaming-SoftwareLogicoolSDKを使ったハンドル入力
https://shin-go.hatenablog.com/entry/logitechunityでLogicoolSDKを使ってLogitech G29 Steering Wheel(ハンコン)を取得したかった話
https://qiita.com/shi_k_7/items/8b2d2e99b4c6d9bc77d4
- 投稿日:2019-10-24T14:02:42+09:00
[C#]Excelファイルのセル読取/書込
D&DしたPDFファイルをSQL Serverに登録+プレビューする方法の記事の一部になります。
4. C#:Excelファイル書き換え
Excelファイルのセル読取/書込処理の忘備録になります。
1) C#でExcelファイルを書き換える方法
大きく分けて、下記の2つがあります。
Microsoft.Office.Interop.Excel
を使った COM 参照による方法- オープンソースライブラリを使用する方法
2) Microsoft.Office.Interop.Excelを使う方法
メリット
- COM 参照なので、現行形式 (.xlsx) だけでなく、旧型式 (.xls)、CSV 形式 (.csv)、マクロ付きも利用可能です。
デメリット
- 処理が遅い
- Excelのインストールが必須
- プロセス解放漏れのリスクがある
サンプルコード
using System.Runtime.InteropServices; using Microsoft.Office.Interop.Excel; class ExcelManager : IDisposable { /// <summary> /// Excel操作用オブジェクト /// </summary> private Application _application = null; private Workbook _workbook = null; private Worksheet _worksheet = null; // Dispose処理は、下記のページを参考にしています。 // [アンマネージドリソースをDisposeパターンで管理する] // (https://days-of-programming.blogspot.com/2018/04/dispose.html) #region "IDisposable Support" private bool disposedValue = false; protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { // TODO: Managed Objectの破棄 } if (_workbook != null) { _workbook.Close(); System.Runtime.InteropServices.Marshal.ReleaseComObject(_workbook); _workbook = null; } if (_application != null) { _application.Quit(); System.Runtime.InteropServices.Marshal.ReleaseComObject(_application); _application = null; } disposedValue = true; } } ~ExcelManager() { Dispose(false); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } #endregion "IDisposable Support" /// <summary> /// Excelワークブックを開く /// </summary> public void Open() { try { // Excelアプリケーション生成 _application = new Application() { // 非表示 //Visible = true Visible = false }; // Bookを開く _workbook = _application.Workbooks.Open(@"e:\book1.xlsx"); // 対象シートを設定する _worksheet = _workbook.Worksheets["Sheet1"]; } catch (Exception ex) { throw (ex); } } /// <summary> /// Excelワークブックをファイル名を指定して保存する /// </summary> /// <returns>True:正常終了、False:保存失敗</returns> public bool SaveAs() { try { // ファイル名を指定して保存する _workbook.SaveCopyAs(@"e:\book2.xlsx"); } catch { return false; } return true; } /// <summary> /// セル設定 /// </summary> /// <param name="rowIndex">row</param> /// <param name="columnIndex">col</param> /// <param name="value">value</param> public void WriteCell(int rowIndex, int columnIndex, object value) { // セルを指定 var cells = _worksheet.Cells; var range = cells[rowIndex, columnIndex] as Range; // 値を設定 range.Value = value; // cell解放 Marshal.ReleaseComObject(range); Marshal.ReleaseComObject(cells); } }参考
Excelファイルを C# と VB.NET で読み込む "正しい" 方法
アンマネージドリソースをDisposeパターンで管理する
Excel操作クラス
Excel操作クラス3) オープンソースライブラリを使用する方法
オープンソースライブラリとして
EPPlus
を想定しています。
(当初はNPOI
を試用しましたが、透過図形がコピーできず、諦めました)メリット
- コア部分が Microsoft の純正ライブラリであるという安心感?
NPOI
よりも扱いやすいデメリット
- Open XML 規格用に作られたものであるため、旧形式ファイル (.xls) を読み込むことができない
準備
メニューの [ツール] - [NuGet パッケージ マネージャー] から、「EPPlus」を検索してインストールします。
サンプルコード
ExcelManagerEx.csusing OfficeOpenXml; class ExcelManagerEx { /// <summary> /// Excel操作用オブジェクト /// </summary> private ExcelPackage _excelPackage = null; private ExcelWorksheet _excelWorksheet = null; /// <summary> /// Excelワークブックを開く /// </summary> public void Open() { try { // Excelファイルを開く var fileInfo = new FileInfo(@"e:\book1.xlsx"); _excelPackage = new ExcelPackage(fileInfo); // シート名で参照 _excelWorksheet = _excelPackage.Workbook.Worksheets["Sheet1"]; } catch (Exception ex) { throw (ex); } } /// <summary> /// Excelワークブックをファイル名を指定して保存する /// </summary> /// <param name="filename">ファイル名</param> /// <returns>True:正常終了、False:保存失敗</returns> public bool SaveAs(string filename) { try { var fileInfo = new FileInfo(filename); _excelPackage.SaveAs(fileInfo); } catch { return false; } return true; } /// <summary> /// セル書込(R1C1形式) /// </summary> /// <param name="row">row</param> /// <param name="col">col</param> /// <param name="value">value</param> public void WriteCell(int row, int col, object value) { // 値を書込 _excelWorksheet.Cells[row, col].Value = value; } /// <summary> /// セル書込("A1"形式) /// </summary> /// <param name="address">address("A1"形式)</param> /// <param name="value">value</param> public void WriteCell(string address, object value) { // 値を書込 _excelWorksheet.Cells[address].Value = value; } /// <summary> /// セル読取(R1C1形式) /// </summary> /// <param name="row">row</param> /// <param name="col">col</param> /// <returns>セルの値</returns> public object ReadCell(int row, int col) { // セル読取 return _excelWorksheet.Cells[row, col].Value; } /// <summary> /// セル読取("A1"形式) /// </summary> /// <param name="address">address("A1"形式)</param> /// <returns>セルの値</returns> public object ReadCell(string address) { // セル読取 return _excelWorksheet.Cells[address].Value; } /// <summary> /// レンジ読取(R1C1R2C2形式) /// </summary> /// <param name="rowFrom">row From</param> /// <param name="colFrom">col From</param> /// <param name="rowTo">row To</param> /// <param name="colTo">col To</param> /// <returns>レンジ</returns> public object[,] ReadRange(int rowFrom, int colFrom, int rowTo, int colTo) { // レンジ読取 return (object[,])_excelWorksheet.Cells[rowFrom, colFrom, rowTo, colTo].Value; } /// <summary> /// レンジ読取("A1:B2"形式) /// </summary> /// <param name="address">address("A1"形式)</param> /// <returns>レンジ</returns> public object[,] ReadRange(string addresso) { // レンジ読取 return (object[,])_excelWorksheet.Cells[addresso].Value; } }test.csusing System; using System.Windows.Forms; public partial class test: Form { public test() { InitializeComponent(); } private void Btn1_Click(object sender, EventArgs e) { var excelEx = new ExcelManagerEx(); excelEx.Open(); // セル書込(R1C1形式) excelEx.WriteCell(row: 1, col: 1, value : "test"); // セル書込("A1"形式) excelEx.WriteCell(address: "A1", value: 3.1415926538); // セル読取(R1C1形式) var cellValue1 = excelEx.ReadCell(row: 1, col: 1); // セル読取("A1"形式) var cellValue2 = excelEx.ReadCell("A1"); // レンジ読取(R1C1R2C2形式) var rangeValue1 = excelEx.ReadRange(rowFrom: 1, colFrom: 1, rowTo: 2, colTo: 2); // レンジ読取("A1:B2"形式) var rangeValue2 = excelEx.ReadRange("A1:B2"); // 2次元配列(0始まり)から要素を参照 var a = rangeValue2[0, 0]; // aには、3.1415926538が入る // 名前を付けて保存する if (excelEx.SaveAs(@"e:\book2.xlsx") == false) { MessageBox.Show("ファイルが既に開かれています。\n閉じてから、再試行してください。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error); } } }参考
- 投稿日:2019-10-24T14:00:17+09:00
[C#]PDF ファイル表示方法
D&DしたPDFファイルをSQL Serverに登録+プレビューする方法の記事の一部になります。
3. C#:Adobe® Readerのコンポーネントの取り込み、その表示
C# でPDF ファイルをフォーム上に表示する方法になります。
リンク先を参考にしています。1) Acrobat® SDK をダウンロードする ( 事前準備 )
下記のサイトから Adobe® SDK を取得します。
Arobat® DC SDK ではPDFを表示できない ( c# WindowsフォームAppでPDF表示ができない。(AxAcroPDFLib) ) ので、Acrobat® XI SDK を使用します。Adobe®のページから、 [Agree and download Acrobat XI SDK for Windows] を選択してダウンロードします。
2) DLL ファイルの取得 ( 事前準備 )
上記で取得した SDK 内のサンプルプロジェクト AcrobatActiveXVB をコンパイルして、以下の2つの dll ファイルが作成します。(VB.NET でのコンパイル)
- AxInterop.AcroPDFLib.dll
- Interop.AcroPDFLib.dll
プロジェクトの参照設定で追加すれば、 PDF ブラウザコントロールが使用できるようになります。
3) PDF ファイルをフォーム上に表示
下記のサンプルコードを参考に表示処理を作成しています。
// ブラウザコントロールの作成 AxAcroPDFLib.AxAcroPDF pdfOcx = new AxAcroPDFLib.AxAcroPDF(); pdfOcx.Dock = DockStyle.Fill; // フォーム全体に表示する this.Controls.Add(pdfOcx); // フォームにコントロールを追加 // PDF ブラウザコントロールに指定したPDFファイルを表示する pdfOcx.LoadFile(@"E:\test.pdf");表示に用いたデータは、[Adobe®公式ページのサンプルPDFデータ] です。
(https://www.adobe.com/content/dam/acom/jp/information/acrobat/taggedpdf/EXR-55_Product_Overview.pdf)下記機能があります。
- 保存
- 印刷
- ページ遷移
- 拡大縮小
- etc
4) 使用許諾
「Acrobat® SDK によって開発されたプラグインやアプリケーションの再配布には、一切の費用は発生いたしません。」と記載されています。
Acrobat® SDK を使用してできることや、SDK に含まれているものについてただし、「詳しくは、下記の文書をご覧ください。」のリンクは切れているようです・・・
参考
[ VB.NET / C# ] PDF ファイルをフォーム上に表示して印刷する
AcroPDFLib.AxAcroPDF 一覧
- 投稿日:2019-10-24T13:58:53+09:00
[C#]ドラッグ&ドロップの使い方
D&DしたPDFファイルをSQL Serverに登録+プレビューする方法の記事の一部になります。
1. C#:ドラッグ&ドロップの使い方
ファイルのドラッグ&ドロップを受け入れる方法。
(内容は、参考に書いたリンクとほぼ同じです)1) UI(デザイン)
2) コード
- [DragDrop] と [DragEnter] イベントハンドラを実装します。
/// <summary> /// DragDropのイベントハンドラー /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void pnlDragAndDrop_DragDrop(object sender, DragEventArgs e) { // DataFormats.FileDropを与えて、GetDataPresent()メソッドを呼び出す。 var files = (string[])e.Data.GetData(DataFormats.FileDrop, false); // GetDataの戻り値はstring型の配列であり、 // 複数のファイルがドロップされた場合には // ドロップされた複数のファイル名が取得できる。 for (int i = 0; i < files.Length; i++) { // GetDataにより取得したString型の配列から要素を取り出す。 var fileName = files[i]; Console.Write(fileName); } } /// <summary> /// DragEnterのイベントハンドラー /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void pnlDragAndDrop_DragEnter(object sender, DragEventArgs e) { // マウスポインター形状変更 // // DragDropEffects // Copy :データがドロップ先にコピーされようとしている状態 // Move :データがドロップ先に移動されようとしている状態 // Scroll:データによってドロップ先でスクロールが開始されようとしている状態、あるいは現在スクロール中である状態 // All :上の3つを組み合わせたもの // Link :データのリンクがドロップ先に作成されようとしている状態 // None :いかなるデータもドロップ先が受け付けようとしない状態 if (e.Data.GetDataPresent(DataFormats.FileDrop)) { e.Effect = DragDropEffects.Copy; } else { e.Effect = DragDropEffects.None; } }参考
- 投稿日:2019-10-24T13:50:15+09:00
Unityでtesseract-4.1.0を使う
ネット上にいくつかtesseractをUnityに導入する記事はあるものの、想像以上に手こずってしまったので備忘録も兼ねて記事にします。
今回使用した環境はWindowsなので、その他の環境では同じ方法でも動かない可能性があります、ご了承ください。そもそもtesseractって?
tesseractとはOCR(Optical Character Recognition、光学文字認識)と呼ばれる画像から文字を認識するためのライブラリの一つで、Apache License 2.0 の下で配布されています。
基本的に内部の言語はC++で書かれているため、Unity上で利用するためにはこれをC#から呼び出せるようにしなければなりません。そこで今回利用したのがDllImport属性です。
DllImport属性を用いるとC#から.dllファイル内の関数を呼び出すことができます。つまり、tesseractを.dllファイルとしてビルドしておけばUnityからその関数を呼び出すことができるということです。tesseractをビルドする
ここから先は実際にtesseractをdllファイルとしてビルドしていきます。
tesseractのダウンロード
GitHubからtesseract-4.1.0のソースコードをダウンロードしてきます。今回は.zip型式でダウンロードしました。
ダウンロード後は通常通り解凍しておきます。これでダウンロード自体は完了です。ビルド環境の構築
次にtesseractをビルドするために必要な環境を構築します。tesseractのwikiにコンパイルの方法が詳しく載っているのでこちらを参考にします。今回はダウンロードしたソースコードからビルドを行うのでGitHubからcloneする必要はありません。また、CPPANやCMakeの環境構築は別の記事が詳しいので本記事では割愛させていただきます。どちらも基本的には公式からダウンロードしてインストール、PATHを通せば完了です。
CPPANおよびCMakeの環境構築が完了した後は、まず先ほど解凍したtesseractフォルダ内のcppan.ymlファイルを変更します。変更するのは5行目です。
cppan.yml(変更前)local_settings: #use_shared_libs: true #short_local_names: true #use_cache: false #generator: Visual Studio 14 2015 Win645行目のコメントアウトを解除して使うVisual Studioの環境に書き換えます。
(今回は64bitのdllとしてビルドしますが、もし32bitのdllとしてビルドする場合は5行目と15行目のWin64をWin32に書き換えてください。)cppan.yml(変更済)local_settings: #use_shared_libs: true #short_local_names: true #use_cache: false generator: Visual Studio 15 2017 Win64上記の変更を加えればビルド環境の構築は完了です。
ビルドする
先ほどのwiki通りにビルドをすれば完了・・・と言いたいところですが、64bitの場合はCMakeコマンドにオプションでWin64であることを指定する必要があります。なので以下のコマンドでビルドすることになります。
cppan mkdir build && cd build cmake .. -G "Visual Studio 15 2017 Win64"cmakeでのビルド完了後はVisual Studioでビルドを行います。先ほど作成したbuildフォルダ内のtesseract.slnファイルを開きます。ソリューションのプロパティから構成がRelease、プラットフォームがx64になっていることを確認(またはそれに変更)してからソリューションのビルドを行います。
特に失敗がなければこれでtesseractのビルドは完了です。作成したdllファイルはbuild/bin/Release内にあるはずです。(既定の設定のままの場合)
Unityでtesseractを使う
先ほどビルドしたtesseractのdllファイルをUnityから使用します。(今回はUnity 2018.4.10f1を使います)
プロジェクトの作成
適当な名前をつけてUnityプロジェクトを作成します。今回はTesseractTestとしました。
プロジェクトが立ち上がったら、まずはAssetsフォルダ内にPluginsフォルダを作成し、先ほど作成した.dllファイルを全てPluginsフォルダ内にいれます。(自環境では33個のdllファイルがありました)
階層の様子は上記のようになるはずです。
次にtesseract-4.1.0フォルダ内にあるtessdataフォルダをまとめてAssetsフォルダにいれます。この時エラーが出ますが無視して大丈夫です。今のままでは学習用データがなく、Unityで実行すると必ずクラッシュしてしまうので今度はtesseractのGitHubのtessdataからとりあえずeng.trainneddataをダウンロードしてこちらもtessdata内にいれます。今回はアルファベットの認識のみとするので、他の言語を使用したい場合は対応した言語のtrainneddataをダウンロードすればいいかと思います。(この辺りはUnity等関係なくtesseract周りの記事が詳しいと思います)OCR用の画像の準備
画像を準備します。今回は以下のような画像で文字認識を行いたいと思います。
※tesseractを使う上での注意点として、文字色が黒で背景が白、または文字色が白で背景が黒でない場合精度がガクッと落ちるそうです。そのためもし色の着いた背景の物を使いたい場合などはその画像を二値変換してからtesseractに渡すといいかと思います。上記の画像をAssetsフォルダにいれ、Inspector内のRead/Write Enableにチェックを入れApplyします。
ゲームオブジェクトの設置
画像を映すためのRawImage、認識した文字を映すためのTextを設置します。RawImageのInspector内のTextureに先ほどAssetsフォルダにいれた画像をD&Dします。このTextureに設定した画像を対象にtesseractで文字認識を行うという形になります。また、動作確認のためCanvasはScreen Space - CameraでMain Cameraの前に表示されるように設定し、適当な位置になるようにRawImageとTextを移動します。
次に空のオブジェクトを設置します。(わかりやすさのためにtesseractという名前にしておきます)スクリプトの作成
適当な位置に空のスクリプトを作成します。今回はOcrFromTexture.csとしました。tesseractのAPIを見つつDllImport属性を用いて関数を呼び出せるようにします。
OcrFromTexture.csusing UnityEngine; using UnityEngine.UI; using System; using System.Runtime.InteropServices; public class OcrFromTexture : MonoBehaviour { [SerializeField] RawImage source; Texture2D texture; [SerializeField] GameObject output; IntPtr ocrHandle = IntPtr.Zero; [DllImport ("tesseract41")] public static extern IntPtr TessBaseAPICreate (); [DllImport ("tesseract41")] public static extern void TessBaseAPIDelete (IntPtr ocrHandle); [DllImport ("tesseract41")] public static extern int TessBaseAPIInit3 (IntPtr ocrHandle, string dataPath, string language); [DllImport ("tesseract41")] public static extern void TessBaseAPISetImage (IntPtr ocrHandle, byte[] imagedata, int width, int height, int bytes_per_pixel, int bytes_per_line); [DllImport ("tesseract41")] public static extern void TessBaseAPISetImage2 (IntPtr ocrHandle, IntPtr pix); [DllImport ("tesseract41")] public static extern IntPtr TessBaseAPIGetInputImage (IntPtr ocrHandle); [DllImport ("tesseract41")] public static extern IntPtr TessBaseAPIGetThresholdedImage (IntPtr ocrHandle); [DllImport ("tesseract41")] public static extern int TessBaseAPIRecognize (IntPtr ocrHandle, IntPtr monitor); [DllImport ("tesseract41")] public static extern string TessBaseAPIGetUTF8Text (IntPtr ocrHandle); [DllImport ("tesseract41")] public static extern void TessDeleteText (IntPtr text); [DllImport ("tesseract41")] public static extern void TessBaseAPIEnd (IntPtr ocrHandle); [DllImport ("tesseract41")] public static extern void TessBaseAPIClear (IntPtr ocrHandle); // Start is called before the first frame update void Start() { /* OCRハンドラの作成と初期化 */ ocrHandle = IntPtr.Zero; ocrHandle = TessBaseAPICreate(); if(ocrHandle.Equals(IntPtr.Zero)) Debug.Log("Error:Cannot Create"); string dataPath = Application.dataPath + "/tessdata"; if(TessBaseAPIInit3(ocrHandle, dataPath, "eng") != 0) Debug.Log("Error:Cannot Init"); /* テクスチャから文字を認識する */ string recognition = RecognizeFromTexture(); output.GetComponent<Text>().text = recognition; } public string RecognizeFromTexture() { /* 画像をTexture2D型として読み込む */ texture = source.texture as Texture2D; Color32[] colors = texture.GetPixels32(); /* 画像データをbyte[]型にする */ int width = texture.width; int height = texture.height; int area = width * height; byte[] bytes = new byte[area * 4]; int point = 0; int index = area - 1; for(int y = height - 1; y >= 0; --y){ for(int x = 0; x < width; ++x){ index = x + y * width; bytes[point] = colors[index].r; bytes[point+1] = colors[index].g; bytes[point+2] = colors[index].b; bytes[point+3] = colors[index].a; point += 4; } } /* byte[]をtesseractに渡して文字認識をする */ TessBaseAPISetImage(ocrHandle, bytes, width, height, 4, width * 4); if(TessBaseAPIRecognize(ocrHandle, IntPtr.Zero) != 0) return null; string result = TessBaseAPIGetUTF8Text(ocrHandle); Debug.Log(result); return result; } }上記のスクリプトを先ほどのtesseractオブジェクトにアタッチし、InspectorからSourceにRawImageオブジェクトを、OutputにTextオブジェクトをD&Dすれば準備は完了です。
Unityでプレイする
上記が終わったら実際にUnityのプレイボタンを押してみます。
実際に文字を認識できていることがわかります。(上側がText、下側がRawImageです)
ただし空白部分は左に詰められてしまうようです。まとめ
tessdataフォルダをUnityにいれていなくてクラッシュして、入れたのにtraieddataが入っていないからクラッシュして・・・と一週間ほど格闘してようやくUnity上でもtesseractを使えるようになりました。
きちんと白黒のはっきりした画像であればそれなりに良い精度で認識できていると感じます。Unity上では動いていたのにUWPとしてビルドしたところ動かなくなってしまったので、(解決策もわからなかったので)tesseractを使うことはなかったとか・・・
- 投稿日:2019-10-24T11:22:42+09:00
NameValueCollerction からクエリストリング文字列を生成する
クエリストリングとは
URL の後ろによくあるやつ
http://xxxxxxx.xx.jp?var1=val1&var2=val2
↑
? から後ろのやつC#でどうやってつくるの?
System.Collections.Specialized.NameValueCollection を使って作れるよ!
やってみた(ダメパターン)
Sample.csvar col = new System.Collections.Specialized.NameValueCollection(); col.Add("var1", "val1"); col.Add("var2", "val2"); Console.WriteLine(col.ToString());よし、できたぞ!
・・・
あれ??
やってみた(成功パターン)
どうやら System.Web.HttpUtility.ParseQueryString メソッドで返却される NameValueCollection を使わないとうまくいかないらしい。
おそらく、返却される NameValueCollection は純粋な NameValueCollection ではないため(だと思う)。Sample.csstring queryString = ""; var col = System.Web.HttpUtility.ParseQueryString(queryString); col.Add("var1", "val1"); col.Add("var2", "val2"); Console.WriteLine(col.ToString());OK!
まとめ
気をつけようね。
- 投稿日:2019-10-24T03:31:57+09:00
Unityで初めて設計にチャレンジして学んだ5つの自分ルール
はじめに
2019年10月のunity1weekゲームジャムで、藝大の友人とゲームを作り、初めてプログラムの設計をしました。
今までに10本程度ゲームを作ってきましたが、設計をせずに作っていたので、完成する頃には混沌としたプロジェクトが出来上がってました。今回のゲームジャムで初めて設計をしてからプログラムを書くということをしてみたので、試行錯誤する中で決めた自分の設計ルールをまとめてみます。
設計の定石なんかがまだ分かってないので、今の時点での自分の知識のみで書きます。(´>ω<`)アドバイスがあれば教えて下さい……。設計の流れ
まずUMLを勉強して、アクティビティ図、シーケンス図、クラス図の読み書きをできるようになった。
- アクティビティ図:プレイ一周分の全てのイベントの流れ(分岐や反復も含めて)を書く。
- シーケンス図 :主にマネージャークラス間の処理のやり取りを書く。
- クラス図 :全てのクラスの変数、メソッド、参照や依存関係を書く。
これらを順に書いてから、Unityで実際にスクリプトを実装していった。
ルール1.マネージャークラスで機能をざっくり管理させる
今回は5つのマネージャークラスを作りました。
全てMonoBehaviorを継承させて、GameManagerオブジェクトにアタッチしました。
- ゲームマネージャー
- UIマネージャー
- キャラクターマネージャー
- サウンドマネージャー
- データベースマネージャー
ルール2.ゲームマネージャーは各マネージャークラスと相互参照する
マネージャークラスでない通常のスクリプトはゲームマネージャーを参照しないし、逆に参照されてもいけないというルールを作りました。
ルール3.その他のマネージャークラス間の参照は自由
UI操作の効果音を鳴らすために、UIマネージャー→サウンドマネージャーへの参照とか。
ルール4.通常のスクリプトは、1つのマネージャークラスを参照する(ゲームマネージャーを除く)
プレイヤーや敵のスクリプトならキャラクターマネージャーを、UIの各ボタンはUIマネージャーを、という感じ。
ルール5.参照していないマネージャークラスの処理は、自分が参照しているマネージャークラスに依頼する
プレイヤーの行動によってUIの音がなるとか。
プレイヤー → キャラクターマネージャー → サウンドマネージャーおまけ 遅延処理はDOTweenで
遅延処理はいつも Invoke() や Coroutine を使っていました。
ただ、引数が使えなかったり、呼び出し先を全てコルーチンで書かなければいけなかったり、不便していました。(´ •ω•`)
そこで、DOTween を導入して、DOVirtual.DelayedCall() を採用したことで、上の2点が解消されました。
さらにコールバック関数に即時関数を使うと、処理を入れ子にできます……!!
20個ぐらいの関数が数珠つなぎになっていたものが、3つにまで減って感動しました。おわりに
Qiita初投稿でドキドキです( ^ω^;)
参考リンク:
- 投稿日:2019-10-24T03:31:57+09:00
Unityで初めて設計にチャレンジして作った5つの自分ルール
はじめに
2019年10月のunity1weekゲームジャムで、藝大の友人とゲームを作り、初めてプログラムの設計をしました。
今までに10本程度ゲームを作ってきましたが、設計をせずに作っていたので、完成する頃には混沌としたプロジェクトが出来上がってました。今回のゲームジャムで初めて設計をしてからプログラムを書くということをしてみたので、試行錯誤する中で決めた自分の設計ルールをまとめてみます。
設計の定石なんかがまだ分かってないので、今の時点での自分の知識のみで書きます。(´>ω<`)アドバイスがあれば教えて下さい……。設計の流れ
まずUMLを勉強して、↓この3つの図を読み書きをできるようにしました。
- アクティビティ図:プレイ一周分の全てのイベントの流れ(分岐や反復も含めて)を書く。
- シーケンス図 :主にマネージャークラス間の処理のやり取りを書く。
- クラス図 :全てのクラスの変数、メソッド、参照や依存関係を書く。
これらを順に書いてから、Unityで実際にスクリプトを実装していきました。
ルール1.マネージャークラスで機能をざっくり管理させる
今回は5つのマネージャークラスを作りました。
全てMonoBehaviorを継承させて、GameManagerオブジェクトにアタッチしました。
- ゲームマネージャー
- UIマネージャー
- キャラクターマネージャー
- サウンドマネージャー
- データベースマネージャー
ルール2.ゲームマネージャーは各マネージャークラスと相互参照する
マネージャークラスでない通常のスクリプトはゲームマネージャーを参照しないし、逆に参照されてもいけないというルールを作りました。
ルール3.その他のマネージャークラス間の参照は自由
UI操作の効果音を鳴らすために、UIマネージャー→サウンドマネージャーへの参照とか。
ルール4.通常のスクリプトは、1つのマネージャークラスを参照する(ゲームマネージャーを除く)
プレイヤーや敵のスクリプトならキャラクターマネージャーを、UIの各ボタンはUIマネージャーを、という感じ。
ルール5.参照していないマネージャークラスの処理は、自分が参照しているマネージャークラスに依頼する
プレイヤーの行動によってUIの音がなるとか。
プレイヤー → キャラクターマネージャー → サウンドマネージャーおまけ 遅延処理はDOTweenで
遅延処理はいつも Invoke() や Coroutine を使っていました。
ただ、引数が使えなかったり、呼び出し先を全てコルーチンで書かなければいけなかったり、不便していました。(´ •ω•`)
そこで、DOTween を導入して、DOVirtual.DelayedCall() を採用したことで、上の2点が解消されました。
さらにコールバック関数に即時関数を使うと、処理を入れ子にできます……!!
20個ぐらいの関数が数珠つなぎになっていたものが、3つにまで減って感動しました。おわりに
Qiita初投稿でドキドキです( ^ω^;)
参考リンク:
- 投稿日:2019-10-24T00:16:51+09:00
脱出ゲームの作り方 7 特定の条件でアイテムを使用
取得した電球を使うと電気が点灯する処理が作成されたが、
LightstandPanel以外の場所でも使えてしまうので、LightstandPanelの場面で電気を使うようにする