1

次のサンプルコードがあります。ベストプラクティスは何ですか?特定のビジネスロジックを実行するには、値を比較するか、タイプを比較します。

public Customer
{
    public Category {get;set;}
    public CategoryName {get;set;}  //e.g. "Category A" or "Category B"
}

public Category{}

public CategoryA : Category {}

public CategoryB : Category {}

public void Main()
{
    Customer customer = new Customer();

// Option 1:
if(customer.CategoryName == "Category A")
{
    CategoryA catA= customer.Category as CategoryA;     
    DoSomething(catA)
}

// Option 2:
CategoryA catA= customer.Category as CategoryA;
if(catA != null)
{
    DoSomething(catA)
}

// Option 3:
if(customer.Catgeory is Category A)
{
    CatgeoryA catA= customer.Category as CategoryA;
    DoSomething(catA)
}
}

コードは説明のためだけのものです。

4

7 に答える 7

4

これらの3つのオプションを考えると、オプション2を使用します。
例-変換を試みて、そうでないかどうかを確認しNullます。

最後のオプションよりも優れている理由は、オプション3isを使用すると、次の行のとの変換と次の行の変換の2つの変換が行われるためasです。

最後に、オプション1は最悪のIMOです。後で固執するかどうか確信が持てないようなロジックが必要です(カテゴリACategoryCategoryNameカテゴリBの顧客を作成することを誰かが妨げているわけではありません。 ")。また、これはオプション2を介してはるかに明確な方法で実行できる追加のロジックです。

他のコメント/回答で指摘されているように、考慮に入れることができるいくつかのオプションがあります。ポリモーフィズムの使用は、おそらく最良の設計戦略です。

于 2012-11-30T13:55:19.130 に答える
3

あなたのデザインに何か問題があると思います。複数のチェックとキャストがあるのは臭いデザインのIMOです。

CategoryA catA = customer.Category as CategoryA;
if(catA != null)
{
    DoSomething(catA)
}

おそらくあなたはDoSomething(CategoryA cat)DoSomething(CategoryB cat)などを持っています。

この場合DoSomething、をカテゴリクラスに移動することを検討することを強くお勧めします。

customer.Category.DoSomething();

CategoryAその後、、、CategoryBおよびによってさまざまな方法で実装できますCategoryC

の実装しかない場合はCategoryA、基本カテゴリに空の実装を設定し、BとCでオーバーライドしないでください。

追加の推奨事項:インターフェースを使用する

私は個人的にベースタイプを実装しません。私はいつもインターフェースを選びます。コードがクラス階層の複数のレイヤーにない場合は、制限が緩和され、従うのが簡単になります。

public interface ICategory{
  void DoSomething();
}

public class CategoryA : ICategory {...}

public class CategoryB : ICategory {...}

インターフェイス実装者間の共通機能?問題ありません。新しいオブジェクトを作成してその機能を実行し、両方の実装者に構成します。次に、その機能を単独で単体テストできます。

于 2012-11-30T14:20:16.283 に答える
1

他の回答者がパフォーマンスやキャストについて1、2回など説明した他のポイントに加えて、いくつか考慮したいと思います。

それは絶対にあなたの特定の場合にビジネスが何をするかに依存します:

a。カテゴリは単なる識別器です

タイプは使用しないでください。Guid文字列、またはaや。のような識別子である必要がありますint。UIのローカリゼーションでは、識別子が人間が読める形式の名前に変換されます。これは、カテゴリで区別するのに十分です。

解決策:顧客にはCategoryNameプロパティがあります。で比較しIdます。

b。カテゴリは識別器であり、可能なカテゴリの数は限られています

一言:列挙Category列挙型を定義します。

public enum Category { A, B, C }

if(customer.Category == Category.A)
{
    // Whatever
}

解決策:プロパティCustomerがありCategoryます。列挙値で比較します

c。カテゴリはエンティティです

カテゴリごとにクラスを作成することはしません。カテゴリはエンティティであり、特定の識別子または名前を持つカテゴリが0個以上あります。

そのため、には、それぞれおよびまたはタイプのCategoryaNameおよびIdプロパティがあります。stringintGuid

解決策:Customerと1:1の関連付けがCategoryありCategoryNameプロパティがあります。で比較しIdます。

于 2012-11-30T14:29:37.673 に答える
0

これは状況によっては少し主観的です。私の意見では、文字列を誤って入力できるという単一の事実については、文字列ではなくタイプで比較する方が常に優れていますが、コンパイラはタイプを誤って入力したかどうかをチェックします。オプション2と3の間では、オプション2で2番目のキャストをスキップする以外に問題はありません。

于 2012-11-30T13:57:33.917 に答える
0

オプション2は、2番目のキャストを節約できるため、オプション3よりも常に優れています。したがって、オプション3を削除できます。

オプション1については、なぜプロパティで型名を複製するのですか?これは冗長なコードです(すでにタイプ名を持っているため)。

したがって、説明したシナリオを考えると、オプション2が最適です。ただし、チェック対象、変更の可能性、カテゴリ名とクラス名の密接な関係などについてもう少し詳しく説明すると、おそらく決定に影響します...

于 2012-11-30T13:57:35.773 に答える
0

編集3:

この質問では、作成者はオブジェクトがPOCOであることを意味していなかったと思います。なぜなら、がPOCOの場合、Category多形になることはできないからです。CategoryAそのため、継承したり、継承したりCategoryBする意味がありませんCategory。なぜ、ポリモーフィズムなしで同じインターフェイスを使用したいのでしょうか。したがって、結論として、この質問の作成者は設計ミスを犯したか、私の元の回答について考える必要があります。

編集2:

Customerの具体的なタイプがわからないことに気づきましたCategory。したがって、次のように使用することはできませんCategoryService

new CategoryService().DoSomething(customer.Category); // compile-time error

したがって、この場合、編集1は無効でした。

編集1:

POCOメソッドのオーバーロードでサービスクラスを使用できるため:

public class Customer {
    public Category Category { get; set; }
}

public abstract class Category {
}

public class CategoryA : Category {
}

public class CategoryB : Category {
}

public class CategoryService {
    public void DoSomething(CategoryA c) {
        Console.WriteLine("A");
    }

    public void DoSomething(CategoryB c) {
        Console.WriteLine("B");
    }
}

オリジナル:

ベストプラクティスはを使用することpolymorphismです。タイプを比較する必要がある場合、それはあなたが何か間違ったことをしたというサインであるか、それは非常に特別な状況です。

public class Customer {
    public Category Category { get; set; }
}

public abstract class Category {
    public abstract void DoSomething();
}

public class CategoryA : Category {
    public override void DoSomething()
    {
        Console.WriteLine("A");
    }
}

public class CategoryB : Category {
    public override void DoSomething()
    {
        Console.WriteLine("B");
    }
}
于 2012-11-30T14:05:05.277 に答える
0

親クラスにオーバーライドメソッドをそのように実装してみませんか?

public override bool Equals(System.Object obj)
{
    bool equal=true;

    //any kind of business logic here on the object values andor types

    return equal;
}

私たちはいつもそれをやっていて、うまくいきます:)

于 2012-11-30T14:36:22.113 に答える