C# 方法重载。你会过度使用它吗?

C# 方法重载。你会过度使用它吗?,c#,java,methods,overloading,C#,Java,Methods,Overloading,当定义几个使用不同过滤器返回相同形状数据的方法时,有什么更好的做法?显式方法名还是重载方法 比如说。如果我有一些产品并且我从数据库中提取 明确方式: public List<Product> GetProduct(int productId) { // return a List } public List<Product> GetProductByCategory(Category category) { // return a List } p

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

比如说。如果我有一些产品并且我从数据库中提取

明确方式:

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    }
public List GetProduct(int-productId){//返回列表}
公共列表GetProductByCategory(类别类别){//返回列表}
公共列表GetProductByName(字符串名称){//返回列表}
超载方式:

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 }
public List GetProducts(){//返回所有产品的列表}
公共列表GetProducts(类别){//按类别返回列表}
public List GetProducts(string searchString){//按搜索字符串返回列表}

我知道您可能会遇到类似签名的问题,但是如果您传递的是对象而不是基类型(string、int、char、DateTime等),那么问题就不会那么严重了。所以重载一个方法是一个好主意吗为了减少你拥有的方法的数量,为了清楚起见,应该以不同的方式过滤数据的每个方法都有不同的方法名

据我所知,你不会有更少的方法,只有更少的名称。我通常更喜欢重载的命名方法系统,但我认为只要您对代码进行良好的注释和记录(在任何一种情况下都应该这样做),这并没有多大区别。

另一种选择是使用查询对象来构建“WHERE子句”。因此,只有一种方法是这样的:

public List<Product> GetProducts(Query query)
公共列表GetProducts(查询)
查询对象包含以面向对象的方式表示的条件。GetProducts通过“解析”查询对象来获取查询


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

我喜欢重载我的方法,这样以后在intellisense中我就不会有太多相同的方法了。在我看来,让它重载比让它以不同的名称命名十几次更符合逻辑。

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

然而,您给出的示例是何时使用方法重载的完美示例。它们都执行相同的功能,为什么仅仅因为要向它们传递不同的类型就给它们不同的名称呢


最主要的规则是做最清楚、最容易理解的事情。不要仅仅为了圆滑或聪明而使用重载,在有意义的时候使用它。其他开发人员可能也在编写此代码。您希望让他们尽可能容易地学习和理解代码,并且能够在不实现bug的情况下实现更改

是的,你可以过度使用它,但是这里有另一个概念可以帮助你控制它的使用

如果您使用的是.NET3.5+,并且需要应用多个过滤器,那么使用IQueryable和链接可能会更好

GetQuery<Type>().ApplyCategoryFilter(category).ApplyProductNameFilter(productName);
GetQuery().ApplyCategoryFilter(类别).ApplyProductNameFilter(产品名称);
这样,您就可以在任何需要的地方反复使用过滤逻辑

public static IQueryable<T> ApplyXYZFilter(this IQueryable<T> query, string filter)
{
     return query.Where(XYZ => XYZ == filter);
} 
公共静态IQueryable ApplyXYZFilter(此IQueryable查询,字符串筛选器)
{
返回query.Where(XYZ=>XYZ==filter);
} 

当方法的参数只有细微的差异时,我看到重载被过度使用。例如:

public List<Product> GetProduct(int productId) { // return a List  }
public List<Product> GetProduct(int productId, int ownerId ) { // return a List  }
public List<Product> GetProduct(int productId, int vendorId, boolean printInvoice) { // return a List  }
public List GetProduct(int-productId){//返回列表}
public List GetProduct(int-productId,int-ownerId){//返回列表}
public List GetProduct(int-productId、int-vendorId、boolean-printInvoice){//返回列表}

在我的小例子中,如果第二个<代码> int >代码>参数应该是所有者或客户ID,很快就不清楚了。你可以考虑的一件事是,不能将重载方法暴露为WCF Web服务中的操作契约。因此,如果您认为可能需要这样做,那么使用不同的方法名称将是一个论据

不同方法名称的另一个理由是,使用intellisense可能更容易发现它们


但是这两种选择都有利弊——所有的设计都是折衷的。

重载的目的是为了简化使用代码的人的学习过程。。。并允许您使用命名方案来通知用户该方法的功能

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

想想.Net框架已经为构造函数和索引器实施了什么。。。它们都必须具有相同的名称,您只能通过重载它们来创建倍数

如果你让他们超负荷工作,他们都会作为一个整体出现,他们的签名和评论都会出现在一旁

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

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

public List GetEmployees(intsupervisorid);
公共列表GetEmployees(内部部门ID);//不允许!!
您可以创建单独的类型作为违规核心类型的包装,以区分签名

  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);
public结构EmployeeId
{ 
私有内部empId;
public int EmployeeId{get{return empId;}set{empId=value;}}
公共EmployeeId(int EmployeeId){empId=EmployeeId;}
}
公共结构部门
  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);
void DeleteFile(string filePath);
void DeleteFile(FileInfo file);
void DeleteFile(DirectoryInfo directory, string fileName);
public IList<Product> GetProductById(int productId) {...}
public IList<Product> GetProductByCategory(Category category) {...}
public IList<Product> GetProductByName(string Name ) {...}
// No collisions, even though both methods take int parameters
public IList<Employee> GetEmployeesBySupervisor(int supervisorId);
public IList<Employee> GetEmployeesByDepartment(int departmentId);
// 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) {...}
public IList<Product> GetProducts() { /* Return all. */}

public IList<Product> GetProductBy(int productId) {...}
public IList<Product> GetProductBy(Category category) {...}
public IList<Product> GetProductBy(string Name ) {...}