36

仲間の開発者は、選択した曜日を 1 と 0 の 7 文字の文字列として保存することを提案しました。つまり、月曜日と金曜日を表す「1000100」です。私は、Flags 列挙型とビット単位の操作を使用したソリューションを好みました (そして強く提案しました)。これは、これを行うためのよりクリーンな方法であり、他の開発者にとって理解しやすいはずです。

  [Flags()]
  public enum Weekdays : int
  {
    Monday = 1,
    Tuesday = 2,
    Wednesday = 4,
    Thursday = 8,
    Friday = 16,
    Saturday = 32,
    Sunday = 64
  }

しかし、サンプル ソリューションの実装を開始したとき、単純な文字列アプローチの方が結局は簡単であることに気付きました。確かに、データだけを見ている場合、ビット文字列は「17」よりも明白です。そして、C# のビット演算は直感に反し、非常に冗長であることがわかりました。

Weekdays workDays = Weekdays.Monday | Weekdays.Tuesday;
if ((workDays & Weekdays.Monday) == Weekdays.Monday) 
{...}

もちろん、これは拡張メソッドにうまくラップできますが、突然、少なくとも文字列ソリューションと同じ数のコード行ができてしまい、ビット単位のコードの方が読みやすいとは言えません。

そうは言っても、私はまだフラグ列挙型とビット単位の操作を使用します。私が考えることができる主な利点は次のとおりです。

  • よりよい性能
  • 保管に必要なスペースが少ない

では、ビット単位のソリューションを同僚に販売するにはどうすればよいでしょうか。するべきか?文字列に対してこのメ​​ソッドを使用することの他の利点は何ですか? サンプル プロジェクトを完了した後、チームがまだ文字列ベースのソリューションを選択していることに気付きました。より良い/より強力な議論が必要です。単純なビット文字列ではなく、Flags 列挙型を使用する必要があるのはなぜですか?

4

6 に答える 6

43

Flags 列挙型を使用する利点:

Flags 列挙型を使用することのマイナス点:

  • 人間にとって理解しにくいデータ表現 (例: 17 にはどのフラグが設定されているか?)


ビット列を使用する利点:

  • プログラマーが文字列に設定されているビットを簡単に確認できます

ビット列を使用することの欠点:

  • 非標準的なアプローチ
  • 設計に慣れていないプログラマーには理解しにくい
  • 「ガベージ」値を設定しやすい可能性があります (例: stringValue = "Sunday")
  • 不要な文字列作成
  • 不必要な文字列解析
  • 追加開発作業
  • 車輪の再発明 (ただし、丸い車輪でさえありません)


ビット列を見て何が設定されているかを確認できることは、どれほど重要なのでしょうか? 17 が月曜日と金曜日であることがわかりにくい場合は、いつでも電卓を使用して 2 進数に変換できます。または、「表示」(またはデバッグ) 用にある種の文字列表現を追加します。それほど難しいことではありません。


また、ビットの文字列をソリッドに近づける場合は、かなりの量のカプセル化を行って、Flags 列挙型が既に提供している抽象化のレベルに引き上げる必要があるように思えます。単純にビット列を直接操作するアプローチの場合、読みにくく (そして理解できず)、おそらくエラーが発生しやすくなります。

たとえば、次のように表示される場合があります。

days = "1000101"; // fixed bug where days were incorrectly set to "1010001"
于 2009-08-17T06:42:25.267 に答える
23

標準データ構造 (この場合、DayOfWeek 組み込み列挙型) を置き換えるために非標準データ構造を作成するべきではありません。代わりに、既存の構造を拡張します。これは、あなたが話していたビット フラグ メソッドと本質的に同じように機能します。

namespace ExtensionMethods
{
    public static class Extensions
    {
        /*
         * Since this is marked const, the actual calculation part will happen at
         * compile time rather than at runtime.  This gives you some code clarity
         * without a performance penalty.
         */
        private const uint weekdayBitMask =
            1 << Monday 
            | 1 << Tuesday
            | 1 << Wednesday
            | 1 << Thursday
            | 1 << Friday;
        public static bool isWeekday(this DayOfWeek dayOfWeek)
        {
            return 1 << dayOfWeek & weekdayBitMask > 0;
        }
    }   
}

これで、次のことができます。

Thursday.isWeekday(); // true
Saturday.isWeekday(); // false
于 2009-08-17T06:38:53.933 に答える
6

平日の組み合わせで開催できるクラスを作ります。クラス内ではどちらの方法でもデータを表すことができますが、文字列ではなくフラグの列挙を使用することは間違いありません。クラスの外では列挙値を使用するだけで、実際のロジックはクラスにカプセル化されます。

何かのようなもの:

[Flags]
public enum Days {
   Monday = 1,
   Tuesday = 2,
   Wednesday = 4,
   Thursday = 8,
   Friday = 16,
   Saturday = 32,
   Sunday = 64,
   MondayToFriday = 31,
   All = 127,
   None = 0
}

public class Weekdays {

   private Days _days;

   public Weekdays(params Days[] daysInput) {
      _days = Days.None;
      foreach (Days d in daysInput) {
         _days |= d;
      }
   }

   public bool Contains(Days daysMask) {
      return (_days & daysMask) == daysMask;
   }

   public bool Contains(params Days[] daysMasks) {
      Days mask = Days.None;
      foreach (Days d in daysMasks) {
         mask |= d;
      }
      return (_days & mask) == mask;
   }

}

使用例:

Weekdays workdays = new Weekdays(Days.MondayToFriday);
if (workdays.Contains(Days.Monday, Days.Wednesday)) {
   ...
}
于 2009-08-17T04:10:58.743 に答える
1

問題は、人間の目でこの保存された値が実際に見えるかどうかに集中する必要があります。もしそうなら、ある程度人間が読める形式が明らかに重要です (ただし、そうであれば、実際の曜日名の配列など、さらに大きなものについて議論します)。

ただし、少なくとも私がこれまでに作成したすべてのアプリでは、この種のデータはどこかの小さなフィールドに入り、C# コードを介する場合を除き、二度と表示されません。つまり、ビットフラグは間違いなく最も単純であり、最も人間的です。コードで読み取り可能。あなたの同僚は、ビルトインで40年以上使用されてきたビット演算のアイデアを使用する代わりに、0 と 1 を値にマップする文字列パーサーを本当に書きたいと思っていますか?

于 2009-08-17T03:02:00.793 に答える
0

Flags メソッドは慣用的です (つまり、経験豊富なプログラマーが行うことであり、少なくとも C/C++/C# 言語では見たり行ったりすることに慣れています)。

于 2009-08-17T03:12:41.760 に答える
0

面白いことに、これらの方法はどちらもまったく同じです。flags メソッドだけがより明白です。

個人的にはフラグを使用します (ただし、モデルによっては、リストを保持している人に対してリストをリストとして保存する方がよい場合もあります)。

- 編集

明確にするために言うと、実際にパフォーマンスを考慮に入れる必要はありません。したがって、最も読みやすいものを使用してください。(これは、名前付きフラグです)。

于 2009-08-17T03:00:45.270 に答える