8

ディレクトリ ツリーを比較するクラスを実装しています (C#)。最初に、クラスのコンストラクターで実際の比較を実装しました。このような:

DirectoryComparer c = new DirectoryComparer("C:\\Dir1", "C:\\Dir2");

しかし、コンストラクターで長時間の操作を実行するのは「適切」ではありません。別の方法は、コンストラクターをプライベートにして、次のような静的メソッドを追加することです。

DirectoryComparer c = DirectoryComparer.Compare("C:\\Dir1", "C:\\Dir2");

どう思いますか?コンストラクターが「速い」ことを期待していますか? 2 番目の例の方が優れていますか、それともクラスの使用法が複雑になっているだけですか?

ところで:

正しい答えはないと思うので、好みと好みだけで、答えを受け入れたものとしてマークしません。

編集:

私の例を少し明確にするために。ディレクトリが異なるかどうかだけでなく、それらがどのように異なるか (どのファイル) にも興味があります。したがって、単純な int 戻り値では十分ではありません。cdragon76.myopenid.com による回答は、実際には私が望むものにかなり近いものです (+1)。

4

14 に答える 14

12

Compare メソッドが比較子自体ではなく比較結果を返すことを期待しているため、2 つの組み合わせが「正しい」選択だと思います。

DirectoryComparer c = new DirectoryComparer();

int equality = c.Compare("C:\\Dir1", "C:\\Dir2");

...そして、Dana が言及しているように、このパターンを反映する .Net にはIComparerインターフェイスがあります。

IComparer クラスは主に並べ替えで使用されるため、IComparer.Compare メソッドは int を返しますただし、一般的なパターンは、次の点で質問の問題に適合します。

  1. コンストラクターは、(オプションで)「構成」パラメーターを使用してインスタンスを初期化します
  2. Compare メソッドは 2 つの「データ」パラメータを取り、それらを比較して「結果」を返します。

これで、結果は int、bool、diff のコレクションになります。ニーズに合ったものは何でも。

于 2008-11-06T20:01:09.063 に答える
10

私は2番目のものを好みます。

コンストラクターがクラスをインスタンス化することを期待しています。メソッド compare は、設計どおりに機能します。

于 2008-11-06T19:56:12.523 に答える
5

インターフェースはあなたが求めているものかもしれないと思います。ディレクトリを表すクラスを作成し、DirectoryComparer インターフェイスを実装します。そのインターフェイスには、compare メソッドが含まれます。C# にすでに Comparable インターフェイスがある場合は、それを実装することもできます。

コードでは、呼び出しは次のようになります。

D1 = new Directory("C:\");
..
D1.compare(D2);
于 2008-11-06T19:58:18.680 に答える
3

コンストラクターで失敗する可能性のあることは、決して実行しないでください。無効なオブジェクトを作成したくありません。オブジェクトがあまり機能しない「ゾンビ」状態を実装することもできますが、複雑なロジックは別のメソッドで実行する方がはるかに優れています。

于 2008-11-06T19:56:14.363 に答える
3

コンストラクター内で長い操作を行わないという一般的な意見に同意します。

DirectoryComparer.Compareさらに、設計に関しては、メソッドがオブジェクト以外のものを返すように、2 番目の例を変更することを検討しますDirectoryComparer。(おそらくDirectoryDifferencesorと呼ばれる新しいクラスDirectoryComparisonResultです。) type のオブジェクトはDirectoryComparer、ディレクトリのペア間の違いを表すオブジェクトではなく、ディレクトリを比較するために使用するオブジェクトのように聞こえます。

DirectoryComparer次に、ディレクトリを比較するさまざまな方法 (タイムスタンプを無視する、読み取り専用属性、空のディレクトリなど) を定義する場合は、これらのパラメーターをクラス コンストラクターに渡すことができます。DirectoryComparerまたは、ディレクトリを比較するためのまったく同じルールが常に必要な場合は、単純DirectoryComparerに静的クラスを作成できます。

例えば:

DirectoryComparer comparer = new DirectoryComparer(
    DirectoryComparerOptions.IgnoreDirectoryAttributes
);
DirectoryComparerResult result = comparer.Compare("C:\\Dir1", "C:\\Dir2");
于 2008-11-06T20:57:22.510 に答える
2

はい、通常、コンストラクターは迅速なものであり、実際に操作を行うのではなく、使用するオブジェクトを準備するように設計されています。1行の操作で済むので、2番目のオプションが気に入っています。

また、コンストラクターが 2 つのパスを渡せるようにしてから、実際に処理を行う Compare() メソッドを使用することで、少し簡単にすることもできます。

于 2008-11-06T19:56:18.280 に答える
1

汎用の比較ツールの場合、構築時に比較するファイルを指定して後で比較するだけでよいと思います。この方法で、拡張ロジックを実装することもできます。

  • もう一度比較してください-ディレクトリが変更された場合はどうなりますか?
  • メンバーを更新して、比較しているファイルを変更します。

また、実装では、ターゲットディレクトリでファイルが変更されたときにOSからメッセージを受信し、オプションで再比較することを検討することをお勧めします。

重要なのは、このクラスがこれらのファイルの単一インスタンスの比較に1回だけ使用されると想定して、制限を課しているということです。

したがって、私は好みます:

DirectoryComparer = new DirectoryComparer(&Dir1,&Dir2);

DirectoryComparer->Compare();

または

DirectoryComparer = new DirectoryComparer();

DirectoryComparer->Compare(&Dir1,&Dir2);

于 2008-11-06T20:04:08.233 に答える
1

2 番目の例は、オブジェクトをインスタンス化するときに何が起こっているかを正確に説明しているため、気に入っています。さらに、私は常にコンストラクターを使用して、クラスのすべてのグローバル設定を初期化します。

于 2008-11-06T20:01:06.133 に答える
1

コンストラクターが有効なオブジェクトを構築するために必要なだけの時間をかけても問題ないと思いますが、コンストラクターはそうする必要があります。オブジェクトの作成を遅らせることは、最終的に無効なオブジェクトになる可能性があるため、非常に悪いことです。そのため、オブジェクトに触れる前に毎回オブジェクトをチェックする必要があります (これは MFC で行われる方法であり、bool IsValid()どこにでもメソッドがあります)。

オブジェクトを作成する 2 つの方法にわずかな違いしか見られません。とにかく、 new 演算子をクラスの静的関数として見ることができます。つまり、これはすべてシンタックス シュガーに要約されます。

クラスは何をしDirectoryComparerますか?その責任は?私の観点 (C++ プログラマーの観点) からは、無料の関数を使用した方がよいように見えますが、C# で無料の関数を使用できるとは思いませんね。目的の異なるファイルを集めることになると思いますDirectoryComparer。その場合は、ファイルの配列またはそれに応じて名前が付けられた同等のクラスのようなものを作成することをお勧めします。

于 2008-11-07T14:30:51.900 に答える
0

引数が一度だけ処理される場合、コンストラクター引数またはインスタンス状態のいずれかに属しているとは思いません。

ただし、比較サービスが何らかの一時停止可能なアルゴリズムをサポートする場合、またはファイルシステムイベントなどに基づいて2つのディレクトリの等価状態が変化したときにリスナーに通知する場合。その場合、それらのディレクトリはインスタンス状態の一部になります。

どちらの場合も、コンストラクターはインスタンスの初期化以外の作業を行いません。上記の2つの場合、アルゴリズムは、たとえばIteratorのようにクライアントによって駆動されるか、イベントリスニングスレッドによって駆動されます。

私は通常、次のようなことを試みます。サービスメソッドへの引数として渡すことができる場合は、インスタンスに状態を保持しないでください。不変の状態でオブジェクトを設計してみてください。equalsやhashcodeで使用されるような属性の定義は、常に不変である必要があります。

概念的には、コンストラクターは、オブジェクト表現をそれが表すオブジェクトにマッピングする関数です。

上記の定義によると、Integer.valueOf(1)== Integer.valueOf(1)であるため、Integer.valueOf(1)は実際には新しいInteger(1)よりもコンストラクターです。、いずれの場合も、この概念は、すべてのcosntructor引数、およびコンストラクター引数のみがオブジェクトのequals動作を定義する必要があることも意味します。

于 2008-11-06T21:02:59.830 に答える
0

操作にかかる時間が不明な場合は、その操作を別のスレッドにエクスポートすることをお勧めします (そのため、メイン スレッドはブロックされず、回転の進行状況インジケーターを表示するなど、他のことを実行できます)。他のアプリはこれを行いたくない場合があり、単一のスレッド内ですべてを必要とする場合があります (たとえば、UI を持たないアプリ)。オブジェクトの作成を別のスレッドに移動するのは、私見では少し厄介です。現在のスレッドでオブジェクトを(すばやく)作成し、そのメソッドを別のスレッド内で実行し、メソッドの実行が終了すると、他のスレッドが終了し、このメソッドの結果を自分のオブジェクトをダンプする前にオブジェクトの別のメソッドを使用して現在のスレッド。

于 2008-11-06T20:34:20.840 に答える
0

C# を使用している場合は、拡張メソッドを使用して、DirectoryClass のビルドにアタッチする 2 つのディレクトリを比較するためのメソッドを作成できます。したがって、次のようになります。

Directory dir1 = new Directory("C:\.....");
Directory dir2 = new Directory("D:\.....");

DirectoryCompare c = dir1.CompareTo(dir2);

これは、より明確な実装になります。拡張メソッドの詳細については、こちらをご覧ください。

于 2008-11-06T20:28:18.340 に答える
0

私は間違いなく2番目にします。

コンストラクターの長いアクションは、実際にオブジェクトを構築して使用できるようにする場合は問題ありません。

現在、人々がコンストラクターで行っていることの 1 つは、仮想メソッドを呼び出すことです。誰かがあなたを基本クラスとして使用し、それらの関数の1つをオーバーライドすると、コンストラクターに入ると、派生クラスではなく基本クラスのバージョンを呼び出すため、これは悪いことです。

于 2008-11-07T14:00:55.363 に答える
0

「長い」などの抽象的な用語について話すことは、コンストラクターに何かを入れるかどうかの決定とは何の関係もないと思います。

コンストラクターは、オブジェクトを初期化するために使用する必要があるものです。メソッドは、「何かを行う」ために使用する必要があります。つまり、関数を持ちます。

于 2008-11-07T14:19:04.937 に答える