web-dev-qa-db-ja.com

メソッドは、(型ではなく)引数名だけで区別できますか?

メソッドを引数の名前(タイプではなく)だけで区別するのに十分ですか、それともより明示的に名前を付けた方が良いですか?

たとえば、T Find<T>(int id)T FindById<T>(int id)です。

引数名だけを維持するよりも、明示的に名前を付ける(つまり、ByIdを追加する)正当な理由はありますか?

考えられる理由の1つは、メソッドのシグネチャが同じでも、意味が異なる場合です。

FindByFirstName(string name)およびFindByLastName(string name)

36
Konrad

もちろん、より明確に名前を付けるのには十分な理由があります。

説明が必要なのは主にメソッドdefinitionではなく、メソッドseです。そして、findById(string id)find(string id)はどちらも一目瞭然ですが、findById("BOB")find("BOB")の間には大きな違いがあります。前者の場合、ランダムリテラルは実際にはIDであることがわかります。後者の場合、あなたは確信が持てません-それは実際には与えられた名前か何か他のものかもしれません。

68
Kilian Foth

FindById()の利点

  1. Future-proofingFind(int)で開始し、後で他のメソッド(FindByName(string)FindByLegacyId(int)FindByCustomerId(int)FindByOrderId(int)など)、私のような人々はFindById(int)を探すために年齢を重ねる傾向があります。本当に問題ではありませんifできますし、必要に応じてFind(int)FindById(int)に変更します-将来の証明はこれらについてですifs。

  2. 読みやすいFindは、呼び出しがrecord = Find(customerId);のようであれば完全に問題ありませんが、record = FindById(AFunction());の場合、FindByIdの方が読みやすいです。

  3. 一貫性FindByX(int)/FindByY(int)パターンはどこでも一貫して適用できますが、Find(int X)/Find(int Y)は競合するため不可能です。

Find()の利点

  • 接吻。 Findは単純明快で、_operator[]_と並んで、このコンテキストで最も期待される2つの関数名の1つです。 (一部の一般的な代替案は、コンテキストに応じて getlookup、またはfetchです)。
  • 経験則として、関数の機能を正確に説明する1つの既知のWordである関数名がある場合は、それを使用します。関数が何をするかを説明するのに少し良い、より長いマルチワード名があったとしても。例: Length vs NumberOfElements 。トレードオフがあり、どこに線を引くかは、現在議論されています。
  • 冗長性を回避することは一般的に良いことです。 FindById(int id)を見ると、冗長性をFind(int id)に変更することで簡単に削除できますが、トレードオフがあり、明確さが失われます。

または、厳密に型指定されたIDを使用して、両方の利点を得るを行うことができます。

_CustomerRecord Find(Id<Customer> id) 
// Or, depending on local coding standards
CustomerRecord Find(CustomerId id) 
_

_Id<>_の実装: C#でID値を強く入力

ここのコメントと上記のリンクから、_Id<Customer>_に関して複数の懸念がありました。

  • 懸念1:ジェネリックの乱用です。CustomerIdOrderIDは異なる型(_customerId1 = customerId2;_ =>良い、_customerId1 = orderId1;_ =>悪い)ですが、それらの実装はほとんど同じです。コピーペーストまたはメタプログラミングを使用して実装できます。ジェネリックの公開または非表示についての議論には価値がありますが、メタプログラミングはジェネリックの目的です。
  • 問題2:単純な間違いを防ぐことはできません。/問題を探すことで解決します強く型付けされたIdを使用することで解消される主な問題は、DoSomething(int customerId, int orderId, int productId)。強く型付けされたIdは、OPが尋ねたものを含む他の問題も防ぎます。
  • 懸念3:それは本当にコードを覆い隠すだけです。 idが_int aVariable_に保持されているかどうかを判別するのは困難です。 Idが_Id<Customer> aVariable_で保持されていることは簡単にわかります。さらに、それが顧客IDであることもわかります。
  • 懸念4:これらのIDは強力な型ではなく、単なるラッパーです。Stringは、_byte[]_の単なるラッパーです。ラップ、つまりカプセル化は、強い型付けと競合しません。
  • 懸念5:過度に設計されています。これが最小バージョンですが、Equalsだけに依存したくない場合は、_operator==_および_operator!=_も追加することをお勧めします。

_public struct Id<T>: {
    private readonly int _value ;
    public Id(int value) { _value = value; }
    public static explicit operator int(Id<T> id) { return id._value; }
}
_
36
Peter

これについてのもう1つの考え方は、言語のタイプセーフを使用することです。

次のようなメソッドを実装できます。

Find(FirstName name);

ここで、FirstNameは、名を含む文字列をラップする単純なオブジェクトであり、メソッドが何をしているのか、それを呼び出す引数に混乱がないことを意味します。

10
3DPrintScanner

FindByIDのような明示的な宣言に投票します。..変更のためにソフトウェアを構築する必要があります。開いて閉じている必要があります(SOLID)。したがって、クラスは開いていて、FindByNameなどの同様の検索メソッドを追加できます。

ただし、FindByIDはクローズされており、その実装はユニットテストされています。

述語を持つメソッドはお勧めしません。述語はジェネリックレベルで優れています。フィールド(ByID)に基づいている場合は、完全に異なる方法論があるとします。

1

次のような述語を使用するよう提案された人がいないことに驚きます。

User Find(Predicate<User> predicate)

このアプローチでは、APIの表面を縮小するだけでなく、それを使用するユーザーにより多くの制御を提供します。

それで十分でない場合は、いつでも必要に応じて拡張できます。

0
Aybe