質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

4回答

2201閲覧

C# 例外処理について

warks1

総合スコア12

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

1クリップ

投稿2018/11/22 00:26

編集2018/11/22 03:43

C#(プログラミング)の勉強中です。
visual studio 2017を使用して
タイマー(Windows.Forms.Timer)を利用して下記のloopを定期的に実行させるプログラムを作成しています。
例外処理のところでよく理解できておらず苦戦していますのでご教授お願いします。

webbrowserでページが表示出来ない・DownloadFileでダウンロード出来ない場合
例外処理が発生すると思いますが、例外処理が発生したときの処理は終了して
再度タイマーの時間がきた際には新規でloopを実行したいです。

現状、下記のソースで可能かと思っていましたが、疎通が取れるようになっても
lavel1が開始にならず、接続エラーの状態になっています。

原因・理由や改善方法等、出来るだけ初心者向けに回答していただけますと幸いです。
お手数おかけしますが回答お願いいたします。

追記

どんな例外処理が発生しても、その処理は終了して再度時間がきた際には1から「loop」の処理を開始したいです。
例えば、物理的にLANケーブルが抜けていた場合、webbrowserコントロールでもDownloadFileでも例外が発生すると思います。その処理は停止します。
途中でLANケーブルを挿しなおせば再度繋がるようになり、その後からタイマーの時間が来た際は例外処理が発生しないと思いますのでその際は普通に処理するという流れが良いです。

現状では挿しなおした後も、例外処理が発生する状態です。

C#

1# using は省略 2 3namespace WindowsFormsApp 4{ 5 public partial class Form1 : Form 6 { 7 // キャンセレーショントークンソース 8 private CancellationTokenSource CancellationTokenSource; 9 //タイマーの宣言 10 System.Windows.Forms.Timer timer2 = new System.Windows.Forms.Timer(); 11 public Form1() 12 { 13 InitializeComponent(); 14 //ボタン 15 button1.Enabled = true; 16 button2.Enabled = false; 17 //タイマー 18 loop(Main_loop); 19 } 20 public void button1_Click(object sender, EventArgs e) 21 { 22 //開始ボタンは有効・停止ボタンは無効 23 button1.Enabled = false; 24 button2.Enabled = true; 25 26 //タイマーのインターバル設定 27 timer2.Interval = intVal * 60000; 28 //タイマー有効化 29 timer2.Enabled = true; 30 } 31 private void button2_Click(object sender, EventArgs e) 32 { 33 //タイマーの停止 34 timer2.Enabled = false; 35 36 //開始ボタンは有効・停止ボタンは無効 37 button1.Enabled = true; 38 button2.Enabled = false; 39 } 40 41 public bool OpenWebWait() 42 { 43 try 44 { 45 //読み込み完了まで待つ 46 while (webBrowser1.IsBusy || webBrowser1.ReadyState != WebBrowserReadyState.Complete) 47 { 48 //無処理 49 System.Windows.Forms.Application.DoEvents(); 50 System.Threading.Thread.Sleep(300); 51 } 52 53 return true; 54 } 55 catch (Exception) 56 { 57 return false; 58 } 59 } 60 61 62 //numericUpDown1 * 60秒 でループするタイマー 63 public void loop(EventHandler eventHandler) 64 { 65 timer2.Tick += new EventHandler(eventHandler); 66 timer2.Enabled = false; 67 } 68 private void Main_loop(object sender, EventArgs e) 69 { 70 try 71 { 72 //TLS1.2を使用・SSL自己証明書のスルー 73 ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(OnRemoteCertificateValidationCallback); 74 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; 75 //ファイルの保存先指定 76 string filepath = (保存先); 77 78 //label1の表示変更 79 label1.Text = "接続中"; 80 label1.Refresh(); 81 82 83 //接続 84 webBrowser1.Navigate(接続先URL); 85 86 //ページの読み込み完了まで待つ 87 OpenWebWait(); 88 89 // クッキーを取得する。 90 string cookieStr = webBrowser1.Document.Cookie; 91 92 // WebClientを生成する。 93 WebClient wc = new WebClient(); 94 Encoding enc = Encoding.UTF8; 95 96 // WebClientのヘッダ設定を行う。 97 wc.Headers[HttpRequestHeader.Cookie] = cookieStr; 98 99 //label1の表示変更 100 label1.Text = "ダウンロード中"; 101 label1.Refresh(); 102 103 //ダウンロード 104 wc.DownloadFile(ダウンロードURL); 105 wc.Dispose(); 106 107 108 109 } 110 catch (Exception w) when (w is ObjectDisposedException || w is InvalidOperationException || w is ArgumentOutOfRangeException || w is COMException) 111 { 112 //label1の表示変更 113 label1.Text = "接続エラー"; 114 label1.Refresh(); 115 116 //Console.WriteLine(w.Message); 117 //1秒待つ 118 Task.Delay(1000).Wait(); 119 } 120 catch (Exception w) when (w is COMException) 121 { 122 Console.WriteLine(w.Message); 123 Application.Exit(); 124 } 125 } 126 127 128 } 129 } 130} 131

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

coco_bauer

2018/11/22 00:34

「lavel1が開始にならず」のlavel1は何で、どのように定義されているのでしょうか? webBrower1,wcなど定義不明な変数が散見されて、プログラムの理解を妨げています。
y_waiwai

2018/11/22 00:45

それに加え、どのような例外が出て、どういう表示がされたんでしょうか
warks1

2018/11/22 01:09

System.Windows.Forms.FormにSystem.Windows.Forms.lavelを設置しています。
izmktr

2018/11/22 01:28

OpenWebWait は何をする関数なんでしょう? これ内部でブロッキングしてませんか?
warks1

2018/11/22 01:31

OpenWebWait を追記しました。ご確認よろしくお願いします。
Wind

2018/11/22 01:34

lavel・・・
Wind

2018/11/22 01:35

Timerを使って、もっとシンプルに例外を再現出来るソースコードを書いてみた方がいいのでは無いでしょうか?
warks1

2018/11/22 01:39

webbrowserコントロールを設置してもらってグーグルでもなんでも指定してLANケーブルを抜いてやっていただければ再現は出来るかと思いますが、、、
guest

回答4

0

基礎的なことを学んでみて今ちょうど欲しい物を付け焼刃の知識で書いてる感じですかね
大抵の人はForm1に実装処理書いてるところから作り直したくなる衝動に駆られるような気がします

全部作るというよりはその中の小さい処理からちゃんと動くかどうかを書いて確認したり、クラス分けをできるようにしていったほうがいいような気がします

ついでに言えばWindowsFormなので全体的に何をしようとしているのかコードだけで判断できない人が多数のようにも感じます

投稿2018/11/23 03:23

DeadEndShoot666

総合スコア203

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

warks1

2018/11/26 00:59

回答ありがとうございます。 クラス分けについても検索してみたりはしたのですが、どうも継承のところが理解しきれておらずうまく出来ませんでした。検索していると簡単なソースであればクラス分けする必要もないとも見ましたが、実際よく分かっていません。ソースが確認しやすくなる他には何か動作的に変わるものがあるのでしょうか。
DeadEndShoot666

2018/11/26 01:29

クラス分けをするとインスタンスを作成して呼び出す必要があるのでよりオブジェクト指向らしい動作になりますが、ソフトの見た目やどういう挙動をするかは何を書くか次第です。可読性が上がればメンテナンス性も向上し、結果的に作業が効率化されるという利点は確実にあります。完成品の予定が掲載しているコードからせいぜい10行程度しか増えないのであれば必要はありません。個人的に今後ボタンを更に追加したり、他の機能を追加したりするんでないかと思ったのでクラス分けを推奨しました。継承は今別に理解しなくてもいいんでないでしょうか。継承がなにかは必要になったとき割とすぐ理解できるので
warks1

2018/11/26 01:51

ご丁寧に回答していただき、ありがとうございます。 すぐに理解して反映させることは難しいですが、クラス分けも今後の課題としてより良いプログラム作成が出来るようにしていきます。
guest

0

以下のTimer.Tickイベントの使い方、正しいのでしょうか?

C#

1 //numericUpDown1 * 60秒 でループするタイマー 2 public void loop(EventHandler eventHandler) 3 { 4 timer2.Tick += new EventHandler(eventHandler); 5 timer2.Enabled = false; 6 }

そもそも、タイマースタート(timer2.Enabled = true;)後、タイマーの時間が来たら(つまりtimer2.Tickのイベントが発生したら)どの処理が走るのでしょうか?
まずはそこを確認するのが先決ではないでしょうか?

投稿2018/11/22 06:38

kenshirou

総合スコア772

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

warks1

2018/11/22 08:29

一部切り取りしてしまったので、そこは問題ないです。 Main_loopを指定しています。 すみません。。
kenshirou

2018/11/22 09:03

eventHandlerはMain_loopなのですね。 ところで、タイマーの使い方ですが、例外が発生したときにタイマーをスタートして、リトライした方がよいのではないかと思います。(もし正常に終了したらtimer2.Enabled = false;で止める) 理由は、例外発生する前にタイマー時間が来てしまったら、DL処理等に支障が出るように思ったからです。 また、タイムアウト用のタイマーが必要であれば、上記とは別に用意した方がよいでしょう。
guest

0

例外の話ではないんですが、設計がまずいという話です

OpenWebWait で待っている間にフォームを閉じようとすると
「アプリケーションが応答していません」ってのが出ませんか?

基本的に、Formsから呼び出された処理は、出来るだけ早く関数を終了しないといけません
それをせずに内部で無限ループを作った場合、いろいろ問題が置きます
ラベルが「開始」にならないのもそれが原因です

なぜなら、ラベルを開始と表示するためには、ラベルを書き換える必要がありますが、
そのためには、ラベルクラスに一旦処理を渡さないといけません
しかし、Windows.Forms.Timerが内部で無限ループを作って、処理を終わらせないので、
ラベルを更新する処理に飛んできません

このような関数の途中でSleepを挟みたい、みたいなことをする場合は、
async/awaitの機能を使う必要があります

投稿2018/11/22 02:04

izmktr

総合スコア2856

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

warks1

2018/11/22 02:43

回答ありがとうございます。 ループ間隔を遅らせればよいでしょうか。 それとも、呼び出すまでループするという考え方自体に問題があるということでしょうか。 理解が出来ず申し訳ありません。 async/await機能を使うとのことですが、具体的な例などいただけないでしょうか。 非同期処理を実施する際に使うものだと認識しているのですが、どう書けば良いかわからない状況です。
izmktr

2018/11/22 02:56 編集

処理が終わるまでループするのが駄目です Sleepするのではなく、returnして、もう一度Forms.Timerから呼び出されたときに続きの処理を行ってください
warks1

2018/11/22 03:45

丁寧に回答していただきありがとうございます。returnの使い方が正直まだ理解できていない為。すぐに対応できそうにないので試行錯誤してみます。
guest

0

タイマーを再設定してないからでは?

投稿2018/11/22 01:34

Zuishin

総合スコア28660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

warks1

2018/11/22 03:44

質問文のソースを具体的に変更しました。 このソースでは再設定できていないでしょうか。
Zuishin

2018/11/22 04:21

質問を読み間違っていたのかもしれません。 ですが、これは最初から作り直したいですね。 全部一度に作ろうとせず、まずはタイマーによる繰り返し処理と例外による停止処理から作ってみてはどうでしょうか? 非同期処理について学ぶのが先決です。 ループ内で CancellationToken を使えば停止できます。 ざっと見たところ、タイマーで時間のたびに最初から処理をしているように見えるので、問題はループが終了しないということでいいんですよね?
warks1

2018/11/22 08:22

タイマーで時間のたびに最初から処理しています。 ↑その動作で問題ありません。原因が自身では分かっていないのですが、例外処理後のタイマー処理の動作が正常に出来ないところが問題に思っています。 今まで、タイマー処理であったりをわけ、以前は非同期処理で行ったりしていたのですが、 理解不足で思った動作が出来ず、現在のソースコードになっています。 どこのサイトが分かりやすいですとか教えていただけないでしょうか。
Zuishin

2018/11/22 10:29

正常にできないというのはどうなるのですか?
warks1

2018/11/26 01:05

返答が遅れてしまい申し訳ありません。 例外が発生した後のmain_loopが動作しない場合があります。 動作している場合もありますししていない場合もあります。 100%動作していないわけではない為、事象を起こそうとしても出来ていない状況です。
Zuishin

2018/11/26 01:18

例外が発生しない場合は必ず動作するのですか?
warks1

2018/11/26 01:48

例外が発生しない場合には、問題なく動作が実行されています。 例外が発生した後の動作だけが正常に動作したりしなかったりしている状況です。
Zuishin

2018/11/26 02:14

失敗する場合、例外はどこで起きていますか? Main_loop の一行目で F9 を押してブレークポイントを設定し、実行して止まったところで F10 を繰り返し押して一行ずつ実行して確認してください。
Zuishin

2018/11/26 02:19

私の予想としては、WebClient を短時間の間にいくつも生成していることでソケットが食いつぶされているのではないかと思っています。
Zuishin

2018/11/26 02:20

その場合、例外が起こったことが原因で動作しなくなるのではなく、動作しないことを示すために例外が起こっているのでしょう。
warks1

2018/11/26 03:01

動作しないことを示すために例外が起こっている場合、どのように対策すれば改善されますでしょうか。
Zuishin

2018/11/26 03:02

まずは原因を特定してください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問