- PR -

[C#]ハッシュ値計算中の進捗率をフォームに返したい

1
投稿者投稿内容
ひろめん
会議室デビュー日: 2009/01/19
投稿数: 10
投稿日時: 2009-01-19 17:57
初めて投稿します。不備があれば申し訳ありません。

C#3.0、Windowsフォームアプリケーションでプログラムしています。

フォームに複数のファイルをD&Dしたときに、それぞれのファイルのSHA1ハッシュ値を計算し、
データクラスのプロパティの一つに、そのハッシュ値を格納したいと考えています。
(データクラスのインスタンスは、ドラッグしたファイル数分作成し、リスト化しています。) (下記コード6行目)

このとき、サイズの大きいファイルのハッシュ値を計算する場合、
結構な時間がかかるため、ProgressBarをフォームに配置し、
1ファイルごとの進捗を表示させたいのですが、
データクラスの生成やリストの管理を、専用のクラス(以下Manager)に任せているため、
Managerからフォームのプログレスバーに値を渡すときの処理がわからなくなってしまいました。
(下記コード21行目)

Managerのコンストラクタの引数にProgressBarを渡すことも考えてみたのですが、
あまりスマートなコードではないと思いますので、できれば避けたいと考えています。

どなたかよい方法をご存知の方は、ご返答いただければ幸いです。
よろしくお願いいたします。

実行可能なコードではありませんが、処理の大体の流れを下記に記しておきます。
コード:
Formクラス:
       //D&D時
 1:    private void Form1_DragDrop(object sender, DragEventArgs e){
 2:        string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); //ドラッグしたファイルを配列に格納
 3:        DataManager manager = new DataManager();                         //データ管理クラスのインスタンス生成
 4:        foreach (string filepath in files){
 5:            Data data = manager.CreateData(filePath);                    //データクラスを生成する (コード12行目へ)
 6:            manager.AddList(data);                                       //リストに追加する
 7:        }
 8:    }

DataManagerクラス:
 9:using System.Security.Cryptography;
10:using System.IO;
11:    //ファイルからデータクラスを作成
12:    public Data CreateData(string filePath){
13:        Data data = new Data();                                                           //データクラスのインスタンス生成
14:        SHA1 sha = new SHA1CryptoServiceProvider();
15:        //省略(FileStreamからbyte配列を作ったり、SHA1クラスでハッシュ値を計算する準備をしたりしています)
16:        //部分計算
17:        byte[] computeBlock = new byte[BufSize];                                          //BufSize=1回に読み進めるバイト数
18:        while (進捗率 < 100){
19:            fileStream.Read(computeBlock, 0, computeBlock.Length);                        //ファイルをBufSize分ずつ読み進めます
20:            offset += sha.TransformBlock(computeBlock, 0, (int)BufSize, computeBlock, 0); //ハッシュ値の部分計算
21:    //→→ここで現在の進捗率を、フォームのプログレスバーに渡したい。
22:    //進捗率自体は全体のファイルサイズとオフセット位置から計算しています。
23:        }
24:        //省略(FinalBlockの計算や、データクラスにデータのセット等を行っています)
25:        return data;                                                                      //データクラスを返す
26;    }

セラフ
ベテラン
会議室デビュー日: 2005/12/01
投稿数: 95
お住まい・勤務地: 東北の顔の形といえば
投稿日時: 2009-01-19 18:34
21行目で自作イベント起こし、フォーム側でそのイベントを拾ってProgressBarを操作

ってのがProgressBar以外も操作できるし、プログレスバー不要の場合は拾わなければいいだけなので、便利で簡単かと思います。
よこけん
大ベテラン
会議室デビュー日: 2006/01/31
投稿数: 216
投稿日時: 2009-01-19 18:53
引用:
ひろめんさんの書き込み (2009-01-19 17:57) より:

Managerのコンストラクタの引数にProgressBarを渡すことも考えてみたのですが、
あまりスマートなコードではないと思いますので、できれば避けたいと考えています。



ProgressBar を直接渡すのは確かによろしくないですね。
そこで、IProgressNotifier なんてインターフェイスを用意してみては如何でしょうか?
Manager クラスのコンストラクタはこのインターフェイスを受け取るようにします。
そして、このインターフェイスの実装クラスが、ProgressBar を操作するわけです。

コード:
public interface IProgressNotifier
{
    void Increment(int value);
}

public class ProgressNotifier : IProgressNotifier
{
    public ProgressNotifier(ProgressBar progressBar)
    {
        this._progressBar = progressBar;
    }
    private readonly ProgressBar _progressBar;
    public void Increment(int value)
    {
        this._progressBar.Increment(value);
    }
}



「依存関係逆転の原則」について調べてみると面白いと思います。

_________________
C#と諸々
ひろめん
会議室デビュー日: 2009/01/19
投稿数: 10
投稿日時: 2009-01-19 21:44
>セラフさん
私自身自作デリゲートや自作イベントを使用したことがないので、
ネットで調べつつ見よう見まねで組んでみました。
任意のメソッドをフォーム側に移すことができましたので、
希望の動きを実装できるようになると思います。
まだ理解が足りないところがありますので、これから解析を進めて行きたいと思います。
情報ありがとうございました。m(__)m
間違えているかもしれませんが、一応試した内容をあげておきます。

コード:
Formクラス:
 1:    private void Form1_DragDrop(object sender, DragEventArgs e){
 2:        DataManager manager = new DataManager();
 3:        manager.hogeEvent  += new DataManager.hoge(manager_hoge);
 4:        manager.CreateData("path");	//13行目へ
 5:    }
 6:
 7:    private void manager_hoge(){
 8:        MessageBox.Show("ほげ〜");
 9:    }

DataManagerクラス:
10:    public delegate void hoge();
11:    public event hoge hogeEvent;
12:
13:    public Data CreateData(string filePath){
14:        Data data = new Data();
15:        if (hogeEvent != null){
16:            this.hogeEvent();
17:        }
18:        return data;
19:    }



2行目、3行目はそれぞれフィールドとコンストラクタで定義したほうが良かったことに気がつきました。
これじゃドラッグイベントが起きるたびにインスタンスができてしまいますねorz。

>よこけんさん
「依存関係逆転の原則」。初耳でした。
インターフェースの使い方は分かっていていも、使いこなすことができていないと実感していますので、
教えていただいたことを元にもうちょっと調べていきたいと思います。
興味深い情報をありがとうございます。

--------------------------------------------------------------------------------------
総合的にお二方の意見をもとに、どうコーディングするか考えてみました。
現状では、最終的に進捗の表示にProgressBarを使うかどうかが確定していません。
よこけんさんのコードで実装すると、インターフェースを実装する
クラスに渡すオブジェクトが固定されてしまいますので、
ProgressBarを渡すようにすると、後で変更が入った時にクラスの中身を
作り直さなければならないような気がします。(機能的に大した量ではありませんが・・・)
今の段階ではイベントを用意しておくだけにとどめておきたいと思います。

お二方とも素早いご返答に感謝すると共に、返答が遅くなったことをお詫びします。
よこけん
大ベテラン
会議室デビュー日: 2006/01/31
投稿数: 216
投稿日時: 2009-01-20 22:02
あ、依存関係逆転の原則は今回ちょっと違ったかも…w
まぁオブジェクト指向の設計原則は抑えておいて損はないので…。
お勧めはこちらの本です。
http://www.amazon.co.jp/dp/4797347783
_________________
C#と諸々
ひろめん
会議室デビュー日: 2009/01/19
投稿数: 10
投稿日時: 2009-01-21 10:31
本屋で探してみて、まずは少し見て見たいと思います。
追加情報ありがとうございます。m(__)m
1

スキルアップ/キャリアアップ(JOB@IT)