【问题标题】:Reuse methods containing same properties but different lambda where clause condition重用包含相同属性但不同 lambda where 子句条件的方法
【发布时间】:2018-01-26 09:50:18
【问题描述】:

这是示例场景,我有 3 个不同的方法,具有不同的参数,但结果是相同的属性类的返回列表。

这是我的代码:

// My Model class:
public class Users{ 
   public string Name{ get; set; }
   public int Age { get; set; }
   public string Location { get; set; }
}

// My Vm class:
public class UserVm { 
   public string Name{ get; set; }
   public int Age { get; set; }
   public string Location { get; set; }
}

这是我的 lambda 查询

// by name
public IEnumerable<UserVm> GetUsersByName (string name){
      return db.Users.Where(x=>x.Name == name).Select(users=>new UserVm{
          Name = users.Name,
          Age = users.Age,
          Location = users.Location
      }).Tolist();
}

// by location
public IEnumerable<UserVm> GetUsersByAge (int age){
      return db.Users.Where(x=>x.Age == age).Select(users=>new UserVm{
          Name = users.Name,
          Age = users.Age,
          Location = users.Location
      }).Tolist();
}

// by age
public IEnumerable<UserVm> GetUsersByLocation (string location){
      return db.Users.Where(x=>x.Location== location).Select(users=>new UserVm{
          Name = users.Name,
          Age = users.Age,
          Location = users.Location
      }).Tolist();
}

如您所见,它们都在视图模型中返回相同的结果。有没有办法像我可以重用那些冗余代码?就像我会放这些代码

return db.Users.Where(x=>x.Location== location).Select(users=>new Users{
          Name = users.Name,
          Age = users.Age,
          Location = users.Location
      }).Tolist();

在一个方法中,但它们的 where 子句在每个调用 main 方法的方法中都不同?

【问题讨论】:

  • GetUsersBy(Func&lt;UserVm, bool&gt; where),例如GetUsersBy(u =&gt; u.Age == 50)
  • 您喜欢为您的用户模型类编写一个构造函数,它接受db.user 并从中设置属性?
  • @ntohl 我已经更新了。是的,它应该是 UserVm :)
  • 我的建议是避免过于笼统。通过使用不同的方法签名,您可以确切地知道自己在做什么,并且可以避免自动化的事情。

标签: c# entity-framework linq lambda


【解决方案1】:

只需将 lambda 表达式作为 Func&lt;Users, bool&gt; 传递给您的查询:

public IEnumerable<UserVm> GetUsers(Func<Users, bool> predicate)
{
      return db.Users.Where(predicate).Select(users=>new UserVm
      {
          Name = users.Name,
          Age = users.Age,
          Location = users.Location
      });
}

另请注意,我已从您的原始代码中删除了 ToList(),因为您无论如何都返回 IEnumerable

你可以这样使用它:

// To get all users under a specific age
var usersVm = GetUsers(u => u.Age < age);

// To get all users with a specific name
var usersVm = GetUsers(u => u.name == name);

顺便说一句:我喜欢在 ViewModel 类中有一个构造函数来获取 Model 类的一个实例,所以我可能会这样写:

public class UserVm { 
   public UserVm (Users model)
   {
       Name = model.Name;
       Age = model.Age;
       Location = model.Location;
   }
   public string Name{ get; set; }
   public int Age { get; set; }
   public string Location { get; set; }
}

然后您的 GetUsers 方法将如下所示:

public IEnumerable<UserVm> GetUsers(Func<Users, bool> predicate)
{
      return db.Users.Where(predicate).Select(user => 
          new UserVm(user));
}

【讨论】:

  • 哈,我还为问题中的 ctor 添加了评论 stronk arm
  • @Nerdintraining'questionmark' 好吧,伟大的思想......(虽然我不得不承认我最喜欢的说法是“扭曲的思想......”)
  • :D 我的思想远非伟大,所以扭曲得更好
  • 非常感谢!这真的很有帮助:) 谢谢你的新学习
  • 很高兴为您提供帮助 ;-)
【解决方案2】:

您可以做的一个简单的事情是在扩展方法中移动 UserVm 对象的创建,您将不再重复对象初始化。

public static class UsersExtensionMethods
{
    public static UserVm ToVm(this User user)
    {
        return new UserVm
        {
            Name = user.Name,
            Age = user.Age,
            Location = user.Location
        };
    }
}

// by name
public IEnumerable<UserVm> GetUsersByName (string name){
      return db.Users.Where(x=>x.Name == name).Select(u => u.ToVm()).Tolist();
}

// by age
public IEnumerable<UserVm> GetUsersByAge (int age){
      return db.Users.Where(x=>x.Age == age).Select(u => u.ToVm()).Tolist();
}

// by age
public IEnumerable<UserVm> GetUsersByLocation (string location){
      return db.Users.Where(x=>x.Location== location).Select(u => u.ToVm()).Tolist();
}

【讨论】:

  • 您的扩展方法将模型连接到视图模型。我不是 MVVM 专家,但我理解它的方式 ViewModel 应该知道模型,但不是相反 - 模型不应该知道 ViewModel。我错了吗?
  • 这就是美丽。因为是扩展方法,所以甚至可以留在UI层。域(模型)将没有关于 Vm 的线索或参考
  • 在我看来,它应该保留在 ViewModel 层中 - 那么有什么比在 ViewModel 类中拥有一个接受模型实例的构造函数更好的呢? (我不会在这里给你带来困难,我真的在问,因为我对 MVVM 很陌生)
  • 没有问题。构造函数参数通常是不好的做法,因为在序列化/反序列化对象时会遇到问题。我喜欢使用 ExtensionMethods,因为通过这种方式,我将 Vm 与 Model 对象分离,并将逻辑(构造)保存在一个地方。而且,扩展方法可以存在于项目中的任何位置,只要它们存在的“层”可以访问PersonPersonVm。我通常有一个 DtoExtensionMethods,它存在于 UI layer 中,并且我根据模型对象生成所有 Dto (Vms)。而且,他们两个之间没有引用
  • @ZoharPeled 没有问题。或者这是一个太长的评论,懒得回复:D
【解决方案3】:

创建一个新方法:

public List<Users> GetUsers(object vmData)
{
   vmData.Select(users=>new Users{
          Name = users.Name,
          Age = users.Age,
          Location = users.Location
      }).Tolist();
}

【讨论】:

    【解决方案4】:

    您可以为过滤创建不同的扩展方法。

    public static IEnumerable<UserVm> FilterByName(this IEnumerable<UserVm> query, string name)
    {
        return query.Where(x => x.Name == name);
    }
    

    并转换为Users 对象:

    public static IEnumerable<Users> ToUsers(this IEnumerable<UserVm> query)
    {
        return query.Select(users => new Users{
            Name = users.Name,
            Age = users.Age, 
            Location = users.Location
        });
    }
    

    这允许您这样称呼它:

    var usersA = db.Users.FilterByName("A").ToUsers().ToList();
    

    可以在fiddle 中找到这方面的一个示例。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-17
      • 1970-01-01
      • 1970-01-01
      • 2012-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-01
      相关资源
      最近更新 更多