System.out.println("またJavaの季節がやってきた!" + 2);
■ このスレッドは過去ログ倉庫に格納されています
去年の今頃Java学習開始するも挫折
しかし不屈の闘志をめらめらと燃やしながら
そびえ立つ岩壁にいどむため、再びこの地にやってきたのだ!
プログラミング歴は独学Cチョビッツ+独学VBA少々
きょうかしょ
https://www.amazon.co.jp/dp/484433638X
スッキリわかるJava入門 第2版 (スッキリシリーズ) あと、今まで知らなかったことを知った
なんでこんなことを知らなかったんだろうと今更ながら衝撃を受けた
VBAで書いたFunctionプロシージャを
ワークシート関数として使う事ができる
これは知らなかった
たぶんVBAやってる人は当たり前に知ってることなんだろうけど
独学でやっていたせいかこんな大事な事を知らなかった
ワークシート関数をVBAのコードで使うと便利だし高速化に繋がることは知っているんだけど
逆があるとは!
ワークシート関数の優れたところは、簡単な記述でリアルタイムにセルに
値を反映させることができる点。
これを使えば、今まで躊躇してきた問題も解決できそうだ VBAのクラスモジュールはほとんど使ったことなかったんだけど
ネットでざっと読んでみるとJavaやC#のクラスと同じような仕組みだとわかる
どちらかというとC#か
以前数回使ったことあるんだけど、あまりよく分からないまま使ってた
オブジェクト指向の言語勉強してからもう一度学び直すと、なるほどなって思える
そこでVBAのもう少し高度な参考書をぽちってみた
入門レベルでは決して足りない実務に必須のスキルとは ExcelVBA 実戦のための技術
単行本 ? 2018/5/24
沢内 晴彦 (著)
今まで作ってきたものを見直すために使えるかもしれない 昔作ったVBAのコードを数時間いじって高速化を試みてみたんだけどことごとく失敗に終わった
高速化とか考えずにとりあえず作ってみたっていうコードが一番速かったという結末
コードの5カ所ぐらいで時間計測してみたら、処理が遅くなっている場所を読み違えていたようだ
ただ、主因となっているところは複雑なコードではなく、改善の余地があまりない
難しいもんだ うぉ・・・高速化成功した・・・
所要時間が1/5に短縮!
5000個ぐらいのセルの値をクリアするコードなんだけど
クリアしちゃだめなセルもある
セルの値が、10パターンぐらいの文字列のどれかに当てはまるなら、そのセルはクリアしちゃダメ
んで、
たぶん一致不一致の判定で時間かかっているんだろうと思って
Likeとアスタリスク使う方法、正規表現使う方法、10パターンの文字列を配列に格納したり
コレクションに格納したり・・・
いろいろやってみたんだけど大差なし
どうやら、実際に消し込む作業に時間がかかっているということが判明
Cells(i, j).Value = "" や Cells(i, j).Clear より
Cells(i, j).ClearContets の方が速いということはわかったんだけど
それ以上の方法が見当たらなかった
で、いろいろググってたんだけど、解決方法は以下の通り
10パターンの文字列は配列だろうがコレクションだろうが大差ないから適当になんかに入れておく
一旦5000個のセル値を配列CellsDataに格納する方向で進むんだけど、
CellsDataの値をひとつずつ10パターンに当てはまるか判定して
当てはまる時だけセル値をCellsDataに入れていく
当てはまらない時は入れないから、そのセルに対応するCellsDataの要素には何も入らないことになる
こうすることで、CellsDataの中身は、必要なセル値を消去した後の表と同じ内容となる
そして、この消去用配列CellsDataを使って、一気に書き込んでいく
Range(Cells(), Cells()) = CellsData
これ↑が突破口だった
よく考えるとこれまで何度か読んだことがある話だったんだけど、思いつかなかった
大量のデータ消去には消去用配列をRangeに一括書き込みすることで高速化が図られるのだ!
これは何も消去だけに限った話ではないのかもしれないんだけど、
単なるデータのセルへの書込みで目立って遅くなったことはない
とするとやはり消去時に特に効果が出る手法なのかもしれない データ書込みも同じようにしたら所要時間がさらに短くなった! 新しく買ってきた本ちょっと読んだけど知らなかったこと多い
Dim i, j as integer
とかいまだにやってる人がいるが・・・・
と書いてあったのだが、はい、わたくしです
知らなかったわぁ
これ i がVariant型になっちゃうそうだ
たぶん勉強始めた頃にこう書いてあったサイトを真似しちゃったんだと思う
こう書いてあるサイトや参考書が結構あるから勘違いしてるひとが多いそうだ
正確には
Dim i As Integer, j As Integer
カウンターぐらいじゃそう問題は起きないかもしれないけど
他の型の変数も同じように定義してきたから
これが原因でわけわかんなくなったエラーもあっただろうな >>515の続きだけど、ワークシートからのデータ取得も
一旦Range型変数に一括取得してから
Rangeから配列に一括代入
そのあと、必要な操作をしたほうがよさそう
今までは必要なデータのみを for や If とかを使って
ワークシートから抽出して配列に代入してた ちょいおかしいか
とにかく不要部分も含めて配列に一括取得してから操作したほうが速いかもって話だ 列挙体便利すぎ
可読性が全然違うわ
セルに書き込んだ設定値を拾って配列に入れて使ってたんだけど
Ary1(1, 1) = Ary2(1, 2) & StrConv(Ary2(1, 1), vbWide)
みたいな書き方してたから、わけわからんコードになってた
今時間見つけては、過去に作ったでかいプログラムを作り直してる
作り直す上での課題はたくさんあって書き切れないんだけど
この前買った本をもう少し読んでから本格的に取りかかった方がよさそうなんだよな
とか言いながらコードどんどん書いちゃってるけど
列挙体はネストができるともっとよかった vbaでクラスモジュールを使う必要性はない、あっても限定的だ
とも言われている
でも、ざっと勉強した感じでは、コードの可読性やメンテナンスのしやすさを考えるとそうとも言えないという印象を持った
一度しっかり使えるようにしておきたいので
実用的なお手本コードを何度か書いてものにしようと思う
参考書にはColectionやDictionaryと組み合わせた処理が書いてあるので
これをちゃんと理解して使えるようにしたい https://qiita.com/pregum/items/071f72969d72d90cf826
ここにもCollectionとDictionaryを組み合わせるコードが載っている
使い方は参考書に載っているものとは違うんだけど、
基本的に大事な事は
DictionaryはExistsメソッドによる検索機能が優れているので
検索機能を強化するために使っているという点
CollectionとDictionaryは似ているので
何のために使い分けているのか把握しておかないといけない
じゃCollectionの利点はというと
Dictionaryと違ってItemのみの登録ができるという点なのか
なので、一次元配列を使おうかという場面でCollectionはいい対抗馬になる
ここに検索機能をつけたい場合は
何かを媒介としてDictionaryとつなげる
ここも参考にした
http://blog.livedoor.jp/minus_alpha/archives/4233055.html ええっと、>>525の何かっていうのは、Collectionのインデックス番号だな
Dictionaryにはこのインデックス番号をItemとし、Keyを検索ワードとして登録していくわけだ
IndexNum = myDic.Exists(検索ワード)
とすると検索ワードに対応するインデックス番号を取得できるので、
こいつを使って、Collectionの要素を参照していく
myCol.Item(IndexNum)
とかいう感じで プログラムの組み直し終わったわ
以前の1/4ぐらいの時間で終了
まぁ以前のコードも参考にしてるから当然なんだけど
改変部分も結構ある
以前より使い勝手がよくなったと思うし処理速度は1/10ぐらいになっている
Dictionaryを組み込んでないのが心残りだわ
やっちゃおうかな・・・メインの部品に組み込んでいくから影響範囲が大きいんだよな んー
VBAでも構造体が使えたのか
これってクラスモジュール使うのと同じような場面で使えるなぁ
https://www.sejuku.net/blog/39307 構造体がデータを格納する機能だけであるのに対して
クラスモジュールはメソッドがついてくるから、その辺まで拡充した役割が必要な時は
クラスモジュールに軍配があがるのかなぁ
あと、セッターで適正値に直したり排除したりできるし
やっぱ複雑なものはクラスモジュールに任せると可読性あがりそう
今回のプログラムも結局クラスモジュールは中心的な処理の中には入れなかったし
これも心残りだわ Dictionary は Exists を目当てに使うのが正解なのもしれない
これ便利
だけど、Key が対象となるわけなので、同じものが重複するようなデータには使えないな
それがネックか ふぅぅぅぅぅ
やっとわかったぜ・・・
ユーザーフォーム上に動的配置したコントロール間で相互にアクセスする方法
もし静的配置であれば簡単で
例えば
TextBox2のクリックイベントプロシージャ内で
MsgBox UserForm1.TextBox1.Value
と書けばいいだけ
動的配置した場合はこういう風にはアクセスできない
今までも動的配置によるコントロール配置はやってきてるんだけど
相互アクセスはやったことがなかった
クラスモジュールにイベントプロシージャを置く事になるんだけど
この中で
動的配置されたテキストボックスのコントロール名を使ってアクセスするというのが解答のようだ
つまり、ユーザーフォームで動的配置したときに、アクセスしやすいように
Nameプロパティで名前をつけておく。
例えばTargetTextとしよう
その上で、クラスモジュールで
Dim tempTextBox as Control
Set tempTextBox = UserForm1.Controls("TargetText")
とすれば
MsgBox tempTextBox.Value
でアクセス可能
疲れたああああああああああああああああああああああああああああああああああああああ ユーザーフォーム上のコントロール動的配置についてもう少し理解を深めるために
単純なプログラムを作ってテストを重ねてみた
ぐぐっても出てこない部分は想像に頼ってるんだけど、大体理解出来たと思う
たまにこういう事をやらないと無駄なコードを書くことになる
今回は今まで書いてたコードの間違いというか、無駄な部分をいくつか見つけたのが収穫だった よし、機能的には大体やりたいこと全部できた
あとはエラーが出ないか現場でチェックだな
一仕事終わった クリップボードを経由しないコピーを勧める理由
http://blog.sbe.tokyo/20150909/470/
なるほどなぁ
こういう考えもあるんだな
確かにいろいろと問題あってめんどくさいとは思っていた
これに関連して
罫線のコピー
http://blog.sbe.tokyo/20150115/203/ VBAでエラー処理をSubプロシージャごとに書いていく作業が刺身にタンポポ乗っける作業と同じぐらい苦痛
これC#で自動化するプログラム書いちゃおうかな
単なる文字列操作だからできるよな
ここ数ヶ月やってなかったんで忘れてしまったが、C#の課題としておくか >>537を参考に罫線をコピーするコードを書いてみたんだけど死ぬほど遅い
やっぱりCopyメソッド使った方がよさそうだ C#の参考書少しずつ読んでるんだけどVBAとダブる部分は
VBAだとどうなのかをメモしてる
この辺ちゃんとやっておかないと記憶があやふやになる VBAとしっかり比較しながらやると勉強になる
C#の知識が増えるころにはVBA忘れる現象に少しは歯止めがかかりそう
というか比較しながらやると知識の固定にも役に立ちそうだわ
除算系の算術演算子とか基本的なのも忘れるからなぁ
独習読み込むのと同時に
C#でちょっとしたウィンドウズアプリ作ってる
URLをテキストボックスに入れてボタン押すと
サーバーにアップロードしてあるZipをダウンロードして解凍して
日付で名前をつけたフォルダに入れるってやつ
こういうのってエラー処理やら利便性無視すれば簡単にできるんだけど
いろいろ考えちゃうと難しくなる
適当なところで見切りつけて終わる予定だけど。
ググって出てくるコードみると、イベントにマルチキャストデリゲートだったか
そんなの使ってたりするんで理解しようとすると大変だ
GUI関連をきちんと理解するのに役に立つ本があるといいな 今日の学習は終わり!
4章の途中まで復習した
switch-case文、
VBAだとSelect Case-Case文
これがたまに混同する
If文の条件式みたいにC#だと丸括弧を使うので注意だな
すぐ忘れる ローカル変数の整数型、初期化しないと
VBAのIntegerだとゼロ
C#のintだとコンパイルエラー
フィールドだとC#はゼロ埋めのようだ
配列も同様
この辺VBAの方が易しい コンソールアプリの強制終了はctrl+c
無限ループになった時とかね delegateをごちゃごちゃいじってる
簡単なプログラムを何個も作ってテストしてる
いろいろ分かってきたわい ラムダ式をごちゃごちゃいじってる
独習のラムダ式の説明はいまいちだな
理解はできたんだけど、これじゃ挫折する人いると思う
デリゲートを用いる最も簡単な例、つまり、メソッドの引数としてメソッドを引き渡すケースではなく
メソッドを変数に代入して使うだけの簡単なケースを
ラムダ式の紹介の一番最初に出してくれないと。
おそらく紙面を節約しないといけない都合でこうなったんだろうけど 配列とかコレクションとかで、全ての要素を順に操作する目的で
ラムダ式が多用されるのな
これ便利だわ
ちなみに独習の標準ライブラリの章で配列にAnyメソッドを使ってる場面があるんだけど
これはListでも使えて、たぶんListにあるExistsメソッドと機能は同じだ
Anyはusing System.Linqが必要
この辺の知識はForの代用として使えるから、すっきりとしたコードをかけるようになれそう ラムダ式の構文でこんなのが独習に書いてある
TResult Func<T, TResult>(T arg)
こういうのをこれまで半ば無視しつつも、時に参考にしてきた
厳密な使い方を理解したいなら、この「構文」とやらをちゃんと理解しておいたほうがいいんだろうなとは思ってる
この構文の形式に近いものがコードに現れてくるのは
ラムダ式で表現されたメソッドを受けとるメソッドの定義部分
例えば
void DoMethod(Func<int, string> output) { Console.WriteLine(output(10)) }
みたいな。
TResult Func<T, TResult>(T arg) において、
<T, TResult> は、T型を引数とし、TResult型を戻り値とする、の意味。ジェネリックだ
頭のTResultは、TResult型の戻り値をおけ、の意味
(T arg)は、T型の引数argをおけ、の意味
argは、argument 引数 の意味
引数というのはparameterじゃなかったっけと思って調べてみたんだけど
argument 実引数
parameter 仮引数
みたいな違いがあるという記述があるという一方
それほど厳密な定義でもないという話も。
エントリーポイントのメインメソッドの引数、つまりコマンドライン引数でも
args として複数の引数を示している
argとかargsが構文に書かれていたら、実際にここに引数を書けということだと理解すれば足りるということだな
少し違和感を感じるのは、なぜ引数だけargという記述を用いて、
戻り値の方はTResultという型しか書いてないのかという点だけど、
まぁこれはよく考えたら、例えば仮引数に変数を使うけど、
戻り値にあらためて変数を使う事はないし、戻り値はメソッド名を書くことで取得できるわけで
そういう意味では、引数にargの記述があり、戻り値にはこういう記述がないのは当たり前か
戻り値を そう考えると、こう書くのが正確なのか
TResult Func<T, TResult>(T arg) において、
Func<T, TResult> は、Func<>の<>の中に2つの型を書けということを示す。そして、
(T arg)の記述により、一つ目のTが引数の型として使われることを説明
構文の冒頭に記述されるTResultの記述により、2つ目のTResultが戻り値の型として使われることを説明
みたいな感じか
まずFunc<T, TResult>という風に書け
そして、TおよびTResultが何なのかを説明するために
TResult Func<T, TResult>(T arg)
というようにFunc<T, TResult>の前後に追加して記述されていると。
順番を意識したほうがよさそうだ LINQで分からないところがあって、ずっと考えてた
やっと分かった(気がする)んで今日はこれで終わろう
もう少しちゃんと説明が書いてあるといいんだけど、難しかったんだろうな
ぐぐってもなかなかヒットしないしね LINQを使う前に、IEnumerable<T>の理解はしておかなきゃね
ということでその辺の復習してる 独習に例示してあるコードは実践的にしたいためか
学習するには要点がぼけてしまってるものがある
なので、自分でぱっとみてポイントが分かるようなコードに書き直して
ちっこくプリントアウトして独習に貼り付けるというアナログなことをしている
なんだかんだいって勉強は紙の方がいいんだよなぁ
検索ができないという点をのぞけばだけどさ
リアル本と電子書籍のハイブリッドなナニカができるといいな
見てくれはリアル本なんだけど、一ページ一ページが電子的な処理が施されていて
印刷内容だけでなくメモった内容も表紙に内蔵されたストレージに保存される
これを使って検索も容易に出来るとか
俺しか需要がないか 頭の中で、抽象クラスというものの存在意義と
ポリモーフィズムがしっかりと関連づけられていなかった
ここがちゃんと結びついてるといろんなルールもすんなり頭に入ってくる (ような気がする あるクラスのプロパティAやメソッドAが、別のクラスBのオブジェクトを返す場合
AとBの名前が同じなことが多いのかな
これまで適当に捉えてたから気づかなかったんだけど、正確に捉えて置いた方がよさそうだ
例えば、
正規表現で、RegexクラスのメソッドMatchがMatchクラスのオブジェクトを返すから
Matchメソッドの構文は
Public Match Match(string input [, int beginning [, int length]])
とMatchが2つ連なっている
で、戻り値として得たMatchオブジェクトというかインスタンスのメンバを使っていろいろと
詳細データを引き出すことになる
なので、最低限この2つのMatchが別物だと認識することは必要 正規表現で
サブマッチ文字列を取り出しすとする
foreach (Group item in m.Groups)
{
Console.WriteLine(item.Value);
}
みたいにするんだけど、このとき、Groupをvarにすると
Valueプロパティが使えなくなる
foreach (var item in m.Groups)
{
Console.WriteLine(item);
}
ならいける
ん〜なんでだろと思って調べてみたんだけど、varを使うとitemにobject型が入るみたいだ
そのため、Group型であれば使えたはずのメンバーが使えなくなる
単純に表示させるだけなら別に問題ないんだけど。
ここで大事なのはvarを使っても具体的な型を使っても同じだと思っていたけど
そうではないケースがあるということだ
上の例だとGroupを使った時はvarを使った時と比べると、6個も追加のプロパティが使えるようになる
複雑な操作を必要とする場合、影響大きいかも 正規表現おもろいなぁと思って
正規表現の聖書と言われているオライリーの「詳説 正規表現」をアマゾンでみたら
\5,184
https://www.amazon.co.jp/dp/4873113598/
ふぇ・・?正規表現だけで5せんえんですか!
しかしそのうち買ってしまう予感がする・・・・ public static void Main(string[] args) {
Console.WriteLine("aaa");
}
みたいなJavaでやってたカッコの付け方に変更できるようだ
Visual Studioの
ツール→オプション→テキストエディタ→C#→書式設定
「始め中カッコ」
という名称があるようだ
変更しようか迷うところだ DateTimeの復習してて令和を含んだ文字列をParseできないか試したけどだめだった
VisualStudioをアプデしたらいけるかなと思ってやってみたら、
これ数ギガ分、つまりファイル全部アプデすんのな
DL待ちで使えなくなってしまった windowsアプデのKB4493453を手動でいれたら、令和認識するようになったわ
var str = "令和1年5月1日";
var d = DateTime.Parse(str);
Console.WriteLine(d);
結果:
2019/05/01(日) 0:00:00 IFormatProviderとかいうのがいろんな構文に引数の型として出てくる
引数の型として指定されているにもかかわらず、実際のコードをみると
「IFormatProvider」という文字はどこにも書かれていない
見て見ぬフリしてたがちゃんと調べてみた
通常はIFormatProviderを実装したクラスであるCultureInfoクラスを利用するようだ
日本独自の表現をしなければならないような場合に使うようだ
例えば日付情報なんか
「2019年」というだけで「年」という日本語を使うので、正確に言えばこういうものを表示する場合だって含まれる
IFormatProvider provider
のようにメソッドの引数として指定されている場合、実際のコードではこう書く
・new CultureInfo("ja-JP")
・CultureInfo.CurrentCulture
・CultureInfo.GetCultureInfo("ja-JP")
のどれでも結果は同じだった
要はIFormatProviderを実装するCultureInfoクラスを使って
日本だってことが伝わればいいようだ var dt = DateTime.Now.AddDays(2);
var ci = new CultureInfo("ja-JP");
ci.DateTimeFormat.Calendar = new JapaneseCalendar();
Console.WriteLine(dt.ToString("f", ci));
結果:
令和元年5月1日 12:03
おぉ・・・でたでた
ci.DateTimeFormat.Calendar = new JapaneseCalendar();
が大事
DateTimeFormatプロパティは戻り値がDateTimeFormatInfoオブジェクト
つまりCultureInfoクラスは、DateTimeFormatInfoオブジェクトをフィールドとしてデータ保持していることになる
そんでもってDateTimeFormatInfoクラスはCalendarプロパティを持っている
CalendarプロパティはCalendar型のフィールドに繋がっている
ここにJapaneseCalendarオブジェクトを代入する
継承Object→Calendar→JapaneseCalendar
だから代入可ということか おっしゃ
実際に役立つアプリができた
ランチャー的なものなんだけど練習にはちょうどいいし
自分で使う分には相当便利で満足
令和の初日に完成か もう1個作った
Javaで作ったやつをC#で作り直したんだけどずっと簡単だった
VSの恩恵を受けてるだけなんだけど。
夏時間も反映する海外の時間も表示する時計なんだけど
ついでにこいつをタイムスケジューラ代わりに使っていこうと思う
Windowsのタイムスケジューラはなぜかそのうち機能停止するので役に立たない webスクレイピングまで行かなくてもhtmlもらってくる処理をしたりするときのお手本コードを
調べてるとasync awaitをつかったものがでてくる
この辺は独習で飛ばしてしまったのでやり直すことにしよう async awaitのところ、独習の説明だと分かったのか分かってないのか分からないという
経験から言えば、これはちゃんと理解できてないなという程度
もう一冊買ってある参考書を読むことにする 実戦で役立つ C#プログラミングのイディオム/定石&パターン
を読んでるんだけど、わかりやすいわぁ
独習は基本的な所を網羅してる点でいいんだけど、少し難しい所に入ると
紙面節約のためか学習の順序ってのをすっとばして説明するから困る
独習もう一度しっかり読んでから実戦を読もうと思ってたけど、
こっちも読み進めていった方が効率あがりそうだ Javaで作った定期的なグローバルIPアドレス記録を時計アプリに組み込んだ
ローカルIPアドレスもついでに記録するようにしたんだけど、これが案外手間取った
あとTimerのインターバルが100mm秒だとなかなか気づけなかった
1秒だと思い込んでた
タイムスケジューラ的な使い方がうまくいくなら
これからはこいつがwindowsのタイムスケジューラのかわりとして利用できることになるわけだ
今回は基本的な非同期処理も取り入れていろいろ勉強になった タスクスケジューラに登録してたのものをすべて時計アプリから実行するようにした
バッチファイルもいけるかなと思っていろいろ調べてやっと問題なく起動できるようになったんだけど
よくよく考えてみたら、exeにコマンドライン引数を渡すためのバッチファイルだった
つまり、普通にexeを時計アプリから引数付きで起動すればいいだけの話だった
もっと言えばそのexeも自分がプログラミングができないから、ネット上から誰かの作ったフリーソフトをダウンロードしたもので、すでにある程度自分でやれるんだから、自作すればいいだけの話なのだが。
少しずつ自作のプログラムに置換えていこうと思う エスケープシーケンス関連の理解が不正確
もっと厳密に理解することにする
なんとなく適当にやってるとできちゃうからよくない Console.WriteLine("aa\naa");//aa[改行]aa
Console.WriteLine("aa\\naa");//aa\naa
Console.WriteLine(@"aa\naa");//aa\naa
Console.WriteLine("aa\daa");//エラー
Console.WriteLine("aa\\daa");//aa\daa
Console.WriteLine(@"aa\daa");//aa\daa
Console.WriteLine((new Regex("aa\naa").IsMatch("aa\naa")));//true(これは特殊な例か)
Console.WriteLine((new Regex("aa\\naa").IsMatch("aa\naa")));//true
Console.WriteLine((new Regex(@"aa\naa").IsMatch("aa\naa")));//true
Console.WriteLine((new Regex("aa\daa").IsMatch("aa1aa")));//エラー
Console.WriteLine((new Regex("aa\\daa").IsMatch("aa1aa")));//true
Console.WriteLine((new Regex(@"aa\daa").IsMatch("aa1aa")));//true
んー正規表現のパターンの中でエスケープシーケンスを用いる場合
基本的には逐語的な表現をしないといけないと思うんだけど、
\nのようにそうでないものもある
上の単純なConsole.WriteLineでの出力で\nについてエラーがでないことと関連するんだろうなぁとは思うんだけど、まぁそういうことなんだろうな 非同期処理async-awaitはC#7.1以降、Mainメソッドでも使えるようになった
しかし、デフォルト設定だと
「最新のメジャーバージョン」を適用することになっているためC# 7.0までしか使えない
そこで、プロジェクトのプロパティ→ビルド→詳細設定から7.1以降を選ぶ
もう一つ
DateTime型は算術演算子を使った比較ができるんだけど
DateTime.Nowを使って取得した現在時と、new DateTime()で取得した固定時間を比較して
イコールになったタイミングで何かをするみたいなことをしようとしてもなぜか一致しない
これは、DateTime型がミリ秒まで格納してるから。
Nowの方はミリ秒が半端なのに対して固定時間はゼロなので、大抵一致しない
そこでミリ秒部分を無視できるように、ToString()でミリ秒がないような文字列に変換して比較するといい
ちなみに、この実験をするときに、VBAでつかったSleepみたいなメソッドがあるといいなと思ったんだけど、
非同期処理をするTask.Delay(1000)を使った方がよいということだ。
これを繰り返し処理と合わせて、1秒おきに処理させて一致させると。
んで、Task.Delayをメインメソッドで使えたら楽できると思って、・・・・最初の話につながる 時計アプリでTimerを使ったんだけど
whileとTask.Delayを組み合わせる方法とどちらがいいんだろうか
そういやTimer使った時、非同期処理なんて考えても行かなかったんだけど
https://qiita.com/kenji-yokoi/items/3115dbf876e6ed30ba50
こんな感じにやったほうがいいわけか
結局どちらの方法を使っても非同期処理をうまくやればいいってことかな >>577
DateTime型は関係演算子を使った比較ができるんだけど* 引き続いてasync-awaitやってるんだけど
自分で適当に練習コード書こうとするといろいろ気づく
Mainメソッドでasyncを使う時
public static async Task Main(string[] args)
みたいにTaskを戻り値の型としないといけない
これをvoidとするとエラー
これは理解できる
C#7.1以前は別にasyncのメソッドを作ってたわけだ
static async Task RunAsync()
みたいなの。
これをMainとかから呼び出す形で使ってたわけだけど
そのままMainに組み込めるようになったということなので
Mainの戻り値がTaskになるのはごく普通
そもそもここをTaskとするのは、そのメソッドを呼び出したメソッドに非同期処理の状況などを
通知するためなんだけど、Mainを呼び出すメソッドに通知するって話になる
ん・・・?ってなるけどここはまぁいいとする
問題は、GUIアプリでつかうイベントハンドラを非同期にした場合
private async void button1_click()
これはなんでvoidなんだ?って話
これがおかしいのかこれは普通でほかがおかしいのか、その辺を突き止めるのがやっかいだったけど
結論としては、イベントハンドラの方が特別で例外的な仕様になっているようだ
ここでvoid Taskとするとエラーがでる
そもそもイベントハンドラを呼び出すのはコードではなくてユーザだから
Taskで通知を返しても意味ないじゃんとかいうことらしい
なるほどね //@
public static async Task Main(string[] args)
{
await Task.Run(() => DoSomething());
}
//戻り値のない同期メソッド
static void DoSomething()
{
var str = "aaabccc";
var result = str.Split('b');
Console.WriteLine(string.Join(".", result));
}
//A
public static async Task Main(string[] args)
{
var str = await Task.Run(() => DoSomething());
Console.WriteLine(str);
}
//戻り値のある同期メソッド
static string DoSomething()
{
var str = "aaabccc";
var result = str.Split('b');
return string.Join(".", result);
}
//B
public static async Task Main(string[] args)
{
await DoSomethingAsync();
}
//戻り値のない非同期メソッド
static async Task DoSomethingAsync()
{
await Task.Delay(2000);
}
//C
public static async Task Main(string[] args)
{
var str = await DoSomethingAsync();
Console.WriteLine(str);
}
//戻り値のある非同期メソッド
static async Task<string> DoSomethingAsync()
{
await Task.Delay(2000);
return "aaa";
} 非同期Mainではwaitは使わないでいいってことかな
呼び出し元でwaitを使うわけだけど
そもそも呼び出し元がないような形になっているのでwaitを使いようがない https://www.kekyo.net/2016/12/06/6186
ここにすごく大事な事が書いてあるような気がする
自分なりにまとめると、
非同期Mainでwaitを使わないでよいのと同じような理由で
GUIアプリのイベントハンドラでもwaitを使わなくてもよい、というようなことになるのかな
使っちゃうと「デッドロック」とやらを引き起こしてしまうそうな
waitをつかわなくちゃだめな例としてはコンソールアプリで非同期メインを使ってないケース
メインメソッドから非同期メソッドを呼び出す
すると、呼び出し先の非同期メソッドではawaitで当該非同期処理の終了を待機することになる
その間にメイン「スレッド」はメインメソッドを抜けてしまってプログラムが終了してしまうことになる
つまり、非同期メソッドの終了を待たずしてプログラム全体が終わってしまうことになる
これは呼び出し元がメインメソッドだからこそ起きるとも言える
@非同期メインでwaitを使う必要がない理由
非同期メインではメインメソッドの中で「await」(waitではなく)を使う事になる
これによってawaitに続く非同期処理が終了するまでメインスレッド自体が待機することになる
これによってメインスレッドが勝手に終了してプログラムが終わってしまうなんてことはないということだ
コンソールアプリで非同期メインを使わないケースでは「await」が置かれているのはメインメソッドではなく、メインメソッドから呼び出される非同期メソッドの中であるという点に注目すれば違いが分かる
この場合は、非同期メソッドの流れがそこでawait(待機)状態になるわけだ
非同期メインではメインメソッド内にawaitが置かれるためメインメソッドの流れがそこでawait(待機)状態になる
A AGUIアプリのイベントハンドラでwaitを使っちゃだめな理由
イメージ的な説明なんだけど、
コンソールアプリで非同期メインを使っているときのメインメソッドと
GUIアプリの非同期イベントハンドラは同じような位置づけになるんじゃないかと。
つまり、
非同期のイベントハンドラ内でawaitを使う事になるので、そこで非同期処理が終わるまで待機してもらえるためwaitの必要がない
これは@とまったく同じこと
いまんところはこういう理解をしている
そのうち変るかもしれないが FileInfoとかDirectoryInfo使う時のパス指定で
「 . 」カレントディレクトリ
「 .. 」一つ上のディレクトリ
が使えるんだけど、一般的ではないのか独習にも書いてない
FileInfoのコンストラクタに渡す引数なんだけど
" data.txt "
" . / data.txt "
" . \data.txt "
この3つはどれを渡してもカレントディレクトリのdata.txtの意味になる
(5ch上では判別しにくいので半角スペースをいれてある)
/ と \ が同じ意味で使えるっていうのは・・・・
さらに
" .. /data.txt "
" .. \data.txt "
この2つはどちらも一つ上のディレクトリのdata.txtを意味する
まさかと思ってやってみたんだけど、
これまで出てきたパス指定なんだけど、¥のかわりに/を使っても大丈夫だった
なら逐語的表現を指定する@を使う必要がなくなるのか
なんで独習には書いてないんだろうか
思い出してきたんだけど、スラッシュをフォルダの区切りとして使うのはもともとUNIXでの書き方か
http://www.tohoho-web.com/ex/draft/path.htm
windowsだとバックスラッシュを使うのが基本
HTMLだと/が使える
この辺は混在してるわけか 地道に独習の復習
やってて思うんだけど、簡単なコードの使い方ぐらいは調べなくても
さっさと書けるようにしないと、難しいコードの使い方を覚えようとしたときに行き詰まるんだよな
記憶力がいまいちだからしっかり覚えるために工夫していかないといけないなと思ってる VBAのプログラム作ってた
windows API呼び出すものなんだけど
DoEventsを使わないとうまく行かないということにやっと気づいた
うまく作れた VBAのプログラム作ってて思うんだけど
windowsAPIを使いこなすための基本知識が欲しい
なんだかんだこぴぺで足りてしまうんでちゃんと勉強してこなかった
何かいい本ないかと思ってアマゾンで検索して
よさそうなのポチろうとしたら、すでに購入済だって表示されててワロタ
今その本発掘してきた これはVBAだけじゃなくて他の言語もやってないと難しいな
ずっと前に少しだけ読んで結局途中で挫折したの思い出した
今読むとそこそこ理解できる
C言語の知識も使うようだ
ずっと昔に少しだけやったけど忘れてしまっている VBAで引数にカッコつけるかどうかの話は大事なんだけど結構忘れる
細かい仕様を理解してないとどうしてこのバグがおきてるのか理解できない
ここはちゃんと押さえないといけないんだが・・・
括弧()はどんなときに使うの?
http://officetanaka.net/excel/vba/beginner/07.htm
もう一つこれ
VBA 関数に引数を渡す
https://www.tipsfound.com/vba/02002
ここの「ByVal と ByRef の違い」の「注意点」ところ
もう一度読んでおかないといけない
これたぶん知らなかったと思う
「これは引数に括弧 () を付けると、強制的に ByVal (値渡し) にする仕様のためです。」
callをつけない場合にバラエティに富んだ動きをするみたい
いままで経験的にcallをつけた方がエラーが起きにくいと思っていたのは
この辺の仕様を理解出来てなかったからだな http://officetanaka.net/excel/vba/statement/Call.htm
myFunctionが引数を受け取り値を返すユーザー定義関数だった場合の書式は、
次のとおりです。
myFunction 123 正常
myFunction(123) エラー
Call myFunction 123 エラー
Call myFunction(123) 正常
rc = myFunction 123 エラー
rc = myFunction(123) 正常
rc = Call myFunction 123 エラー
rc = Call myFunction(123) エラー
こう書いてあるんだけど、2番目のこれ
myFunction(123) エラー
実際にVBEで書くとこんな感じに半角スペースが自動的に挿入されて表示される
myFunction (123)
でもって、エラーなしで通ってしまう
myFunctionの中身次第で通らないこともあるのかもしれないんだけど、解釈としてはこう
myFunction 123 '戻り値を利用しないからカッコをつけないパターン
myFunction(123) '戻り値を利用しないからカッコをつけるとエラー(しかし実際にはこう書くことはできない)
myFunction (123) '戻り値を利用しないからカッコをつけると本来エラーなのだが、半角スペースが自動ではいることで、このカッコは別の意味を持つ。つまりこのカッコはByValを強制するカッコとなる。 Win32APIの知識はVBAだけじゃなくて他でもそのうち役に立つかもしれない
と思ってやってるんだけど、それより
C言語が絡んできたのが面白い
まさかVBAやっててC言語の知識を使うとは思わなかった
ある言語から他言語を使うようなパターンは今まで一度もやったことがなかったから
そういう意味でも面白い
固定長のnull埋めされた文字列を定義して渡したあと
戻ってきた文字列からnullを抜いた残りを取り出すとか またVBAのプログラム作ってた
正規表現盛りだくさんやつ
やっぱ正規表現の本買っちゃおうかなぁ
これ使えるわ あーまたVBAにはまってきた
C#と文法がぐちゃぐちゃになって次第にVBA勢に脳内が支配されて・・・・
うがああああああああ
functionの作り方で、配列とかを引数としてfunctionに渡して適切な値を入れてもらう
んで戻り値をbooleanにして成否を伝えるっていう
Win32APIの勉強しててこのパターンがよく出てきたんで真似てみたんだけど悪くない たくさんプログラム作ってると、以前作ったもののメンテナンスしないと
いけない場面によく出くわすんだけど
共通した処理を関数に切り出したり、共通した値を定数として宣言したりするのってほんと大事だ
昔つくったのはこの辺ができてないから、少しいじるだけでも大変
いろんな所に同じものが散らばってるから全部直さないといけない
メンテナンスまでやると大事さがわかってくるなぁ VBAのプログラムを3つ同時に作ってる
一つは昔作ったやつで、これまでは使われてなかった
でも使う事になったんで見直したらいろいろいじりたくなってきた
マジックナンバーが多すぎるし共通部分の洗い出しが全然できてない
これじゃメンテナンスに苦しむのは目に見えてる
今後変更されそうな部分は簡単に取っ替えられるようにしておかないとね
ほんとはもっと大きくいじってもよさそうなんだけどキリがない
10個ぐらいのデータを並べて1セットとして
このセットを1ページに複数行複数列タイルを貼るかのように
並べていくパターン
この処理が3つのシートそれぞれにあって、それぞれ別個のコードを書いてた
セットの中身も違うし、並べるタイルの数も違うんだけど
これを一般化して関数として作り直した
数列の一般項を求めるのがポイント
関数に渡す引数が多いので構造体を使って一気に引き渡すと同時に
構造体によるインテリセンスによって間違いを減らす
これによって、タイルの中身が変更されたときにもすぐに対応できるし
タイルの並べ方が変更されても与える定数を変更することで簡単に対応できる
ちなみにこれまでのコードでは、
タイルを並べるような概念はなくて、項目のひとつひとつを適切な場所に個別に配置していくパターン
セットの並べ方が変ると、10項目ひとつひとつについて修正が必要になっていた
コードの見通しも悪かった オライリーの詳説正規表現買っちまったぜ・・・・正規表現だけで5せんえんとか・・・ VBAのコード書いてると
配列は全部要素番号1からの方が処理しやすくて統一してるんだけど
ほかの言語やるとゼロからだし、VBAだってsplitが返す配列はゼロから始まるし
やぱ配列はゼロからに統一したほうがいいのかなって最近考えてる
どの言語やるにしても必ずゼロから始まると意識して気をつけてれば慣れるものかもしれないし 今日はいろいろテクを学んだ
配列関連だから今後使えると思う
Rangeで列や行を一括取得したときに作られてしまう二次元配列を
1次元配列にする方法
とか
あとListBoxにアイテム追加するのにAddItem使ってたけど
これ表示がバグることがあるんで、Rangeや配列から一括代入したほうがよさそう
バグらなくなったんでたぶんこうしたほうがいいんだと思った ん〜まだまだ完成しないな
少しずつやっていくしかない
大分進んで、構造的なものも明確になってきたんで
あとは間違いないように組んでいくだけだ よーし、大体できたぞー
あとは細かいバグがないかチェックしないと 俺が以前作った使えなさそうなプログラムが知らない所で意外な活躍をしてた
役にたつことはあまりなさそうなものでも
使う人が用途を見つけた途端にとんでもないものに化けるから面白い
がちがちに固めずふんわり系のインフラ的ソフトは特にね ん〜大体これでいいかな
つけた方がいい機能は全部つけた
やっぱ入力フォームは鬼門だなぁ
各コントロールが複雑に入り組んでて制御が大変だ
特にListBoxがらみ
でもこれで大きなバグは潰したと思うから
これ以上でないことを祈るばかり・・・・ ■ このスレッドは過去ログ倉庫に格納されています