方法重载.你能过度使用它吗?

Arm*_*est 37 c# java methods overloading

在定义使用不同过滤器返回相同形状数据的多个方法时,有什么更好的做法?显式方法名称或重载方法?

例如.如果我有一些产品,我从数据库中提取

明确的方式:

public List<Product> GetProduct(int productId) {    // return a List    }
public List<Product> GetProductByCategory(Category category) {    // return a List    }
public List<Product> GetProductByName(string Name ) {    // return a List    }
Run Code Online (Sandbox Code Playgroud)

重载方式:

public List<Product> GetProducts() {    // return a List of all products    }
public List<Product> GetProducts(Category category) { // return a List by Category }
public List<Product> GetProducts(string searchString ) { // return a List by search string }
Run Code Online (Sandbox Code Playgroud)

我意识到你可能会遇到类似签名的问题,但是如果你传递的是对象而不是基类型(string,int,char,DateTime等),这将不再是一个问题.所以...是一个好主意,重载的方法来减少你有方法和清晰的数字,或者应该每种方法是对数据进行过滤以不同的方式有不同的方法名

Bev*_*van 44

是的,重载很容易被滥用.

我发现确定过载是否合理的关键是考虑受众 - 而不是编译器,而是维护程序员将在几周/几个月/几年内出现,并且必须了解代码是什么试图实现.

一个简单的方法名称,如GetProducts()是清晰易懂的,但它确实留下了很多未说明的内容.

在许多情况下,如果传递给GetProducts()的参数命名良好,维护人员将能够计算出重载的作用 - 但这依赖于在使用点的良好命名规则,而您无法强制执行.您可以强制执行的是他们调用的方法的名称.

我遵循的指导原则是只有在可以互换的情况下才重载方法 - 如果他们做同样的事情.这样,我不介意我班级的消费者调用哪个版本,因为它们是等价的.

为了说明,我很乐意为DeleteFile()方法使用重载:

void DeleteFile(string filePath);
void DeleteFile(FileInfo file);
void DeleteFile(DirectoryInfo directory, string fileName);
Run Code Online (Sandbox Code Playgroud)

但是,对于您的示例,我将使用单独的名称:

public IList<Product> GetProductById(int productId) {...}
public IList<Product> GetProductByCategory(Category category) {...}
public IList<Product> GetProductByName(string Name ) {...}
Run Code Online (Sandbox Code Playgroud)

拥有全名使得代码对于维护人员(可能是我)更明确.它避免了签名冲突的问题:

// No collisions, even though both methods take int parameters
public IList<Employee> GetEmployeesBySupervisor(int supervisorId);
public IList<Employee> GetEmployeesByDepartment(int departmentId);
Run Code Online (Sandbox Code Playgroud)

还有机会为每个目的引入重载:

// Examples for GetEmployees

public IList<Employee> GetEmployeesBySupervisor(int supervisorId);
public IList<Employee> GetEmployeesBySupervisor(Supervisor supervisor);
public IList<Employee> GetEmployeesBySupervisor(Person supervisor);

public IList<Employee> GetEmployeesByDepartment(int departmentId);
public IList<Employee> GetEmployeesByDepartment(Department department);

// Examples for GetProduct

public IList<Product> GetProductById(int productId) {...}
public IList<Product> GetProductById(params int[] productId) {...}

public IList<Product> GetProductByCategory(Category category) {...}
public IList<Product> GetProductByCategory(IEnumerable<Category> category) {...}
public IList<Product> GetProductByCategory(params Category[] category) {...}
Run Code Online (Sandbox Code Playgroud)

代码读取的次数比写入的要多得多 - 即使您在初始检查源代码控制后再也没有回到代码中,在编写代码时,您仍然会读取该行代码几十次.随后的代码.

最后,除非您正在编写一次性代码,否则您需要允许其他人使用其他语言调用您的代码.似乎大多数业务系统最终都会在日期之前保持生产状态.可能是2016年消耗你的类的代码最终是用VB.NET,C#6.0,F#或者尚未发明的全新内容编写的.可能是该语言不支持重载.

  • 非常好的帖子有很多例子.谢谢! (4认同)
  • +1优秀的建议,全心全意地同意.没有实际需要的方法重载是邪恶的.我要补充一点(至少在Java中)它在setter中更加邪恶 (2认同)

Eli*_*lie 16

据我所知,你不会有更少的方法,只有更少的名字.我通常更喜欢重载的命名方法系统,但我认为只要你很好地评论和记录你的代码(在任何一种情况下都应该这样做),它并没有太大的区别.


ste*_*yer 15

你能过度使用它吗?嗯,是的,这是真的.

但是,您给出的示例是何时使用方法重载的完美示例.它们都执行相同的功能,为什么只是因为你将不同的类型传递给它们而给它们不同的名称.

主要规则是做最清楚,最容易理解的事情.不要使用重载只是为了光滑或聪明,在有意义的时候去做.其他开发人员也可能正在处理此代码.您希望让它们尽可能简单地获取并理解代码,并能够在不实现错误的情况下实现更改.


小智 11

我喜欢重载我的方法,以便以后在intellisense中我没有相同的方法.对我来说,让它过载而不是让它的命名方式不同十几次似乎更合乎逻辑.


flo*_*rin 5

您可能需要一些项目范围的标准。就个人而言,我发现重载的方法更容易阅读。如果您有 IDE 支持,那就去吧。


Joe*_*Joe 5

您可以考虑的一件事是您不能将重载的方法公开为WCF Web服务中的操作契约.因此,如果您认为您可能需要这样做,那么使用不同的方法名称将是一个争论.

不同方法名称的另一个论点是使用intellisense可以更容易地发现它们.

但两种选择都有利弊 - 所有设计都是权衡取舍.


cha*_*ana 5

重载的目的是缓解使用您的代码的人的学习曲线......并允许您使用命名方案来通知用户该方法的作用。

如果您有十种不同的方法都返回一组员工,那么生成十种不同的名字,(特别是如果它们以不同的字母开头!)会使它们在用户的智能感知下拉菜单中显示为多个条目,从而延长了下拉,并隐藏所有返回员工集合的十个方法集与类中的任何其他方法之间的区别......

想想.Net 框架已经为构造函数和索引器强制执行了什么……它们都被迫具有相同的名称,并且您只能通过重载它们来创建多个……

如果您超载它们,它们将全部显示为一个,并且将它们不同的签名和注释放在一边。

如果两个方法执行不同或不相关的功能,则不应重载它们...

至于当您想按类型重载具有相同签名的两个方法时可能存在的混淆

public List<Employee> GetEmployees(int supervisorId);
public List<Employee> GetEmployees(int departmentId); // Not Allowed !!
Run Code Online (Sandbox Code Playgroud)

好吧,您可以创建单独的类型作为违规核心类型的包装器以区分签名。

  public struct EmployeeId 
  { 
      private int empId;
      public int EmployeeId { get { return empId; } set { empId = value; } }
      public EmployeeId(int employeId) { empId = employeeId; }
  }

  public struct DepartmentId 
  {
   // analogous content
  }

 // Now it's fine, as the parameters are defined as distinct types...
 public List<Employee> GetEmployees(EmployeeId supervisorId);
 public List<Employee> GetEmployees(DepartmentId  departmentId);
Run Code Online (Sandbox Code Playgroud)