Linq:基于类型A的对象筛选类型A的列表?

时间:2017-05-15 21:55:40

标签: c# linq

我有一个类型为Foo的对象列表,以及一个类型为Foo的对象的另一个实例。我想使用linq根据实例的非null属性过滤列表。

class Foo {
  public int ID;
  public string Description;
  public long Location;
}

Foo fooFilter = new Foo() {
  ID = null,
  Description = null,
  Location = 1
}

List<Foo> fooList = new List<Foo>();

fooList.Add(new Foo(){ID = 1, Description = "one", Location = 1});
fooList.Add(new Foo(){ID = 2, Description = "two", Location = 0});
fooList.Add(new Foo(){ID = 3, Description = "three", Location = 1});

List<Foo> filteredFooList = fooList.Where(???);

我想以某种方式使用fooFilter查询fooList并填写filteredFooList

[
  {ID = 1, Description = "one", Location = 1},
  {ID = 3, Description = "three", Location = 1}
]

修改

我试图简短地提出这个问题,但我可能留下了重要的信息。在我的实际程序中,List<Foo>是来自数据库的大量结果(超过40k条目)。我正在尝试创建一个控制器方法(MVC),它可以采用与实体框架对象的字段名称匹配的任何参数组合。所以<Foo>是EF记录类型。所以我试图避免必须明确列出可以在控制器中过滤的所有(15个左右)字段:

public class Home : Controller
{
  public ActionResult FilteredFooList(int ID, string Description, long Location, etc, etc, etc)
    {

    }
}

做更多的事情:

public class Home : Controller
{
  public ActionResult FilteredFooList(Foo filterObj)
    {

    }
}

也许这不可能或不是一个好主意?

5 个答案:

答案 0 :(得分:2)

如果您只想过滤掉非实例属性,则不需要过滤器。

class Foo
{
    public int ID;
    public string Description;
    public long Location;

    public bool IsInstanciated()
    {
        return this.ID != default(int) && this.Description != default(string) && this.Location != default(long);
    }
}

List<Foo> filteredFooList = fooList.Where(f => f.IsInstanciated());

<强> 编辑: 如果你真的需要使用那个instanciated类作为过滤器,我建议你使用IEquatable<T>

class Foo : IEquatable<Foo>
{
    public int ID;
    public string Description;
    public long Location;

    public bool Equals(Foo other)
    {
        // Whatever your logic is
        return string.IsNullOrEmpty(this.Description) == string.IsNullOrEmpty(other.Description) && 
               this.ID > 0 == other.ID > 0 && 
               this.Location > 0 == other.Location > 0;
    }
}

public class Home : Controller
{
    public ActionResult FilteredFooList(Foo filterObj)
    {
        List<Foo> filteredFooList = fooList.Where(f => f.Equals(filterObj));
    }
}

答案 1 :(得分:1)

不要通过向数据对象添加不必要的属性来使自己陷入困境,他们应该保留数据对象。您有效地尝试构建动态查询,您希望通过条件列表有条件地过滤。有这样的模式。

从基本查询开始,然后确定是否要按其中一个属性进行过滤。对其他属性执行相同操作。当你到达终点时,你可以收集结果。

var filter = new Foo
{
    ID = null,
    Description = null,
    Location = 1,
};

var data = new List<Foo>
{
    new Foo { ID = 1, Description = "one", Location = 1 },
    new Foo { ID = 2, Description = "two", Location = 0 },
    new Foo { ID = 3, Description = "three", Location = 1 },
};

var query = data.AsEnumerable();
if (filter.ID != null)
    query = query.Where(x => x.ID == filter.ID);
if (filter.Description != null)
    query = query.Where(x => x.Description == filter.Description);
if (filter.Location != null)
    query = query.Where(x => x.Location == filter.Location);

var result = query.ToList();

这假设IDLocation实际上可以为空,就像您的示例所暗示的那样。

public class Foo
{
    public int? ID { get; set; }
    public string Description { get; set; }
    public long? Location { get; set; }
}

答案 2 :(得分:0)

假设您可以将值类型更改为可为空:

class Foo {
    public int? ID;
    public string Description;
    public long? Location;
}

然后你可以使用一些扩展名:

public static class Ext {
    public static bool EqualOrNull<T>(this T? value, T? filter) where T : struct, IComparable {
        return (filter == null) || (value.Value.CompareTo(filter.Value) == 0);
    }
    public static bool EqualOrNull<T>(this T value, T filter) where T : class, IComparable {
        return (filter == null) || (value.CompareTo(filter) == 0);
    }
}

要做到这一点:

var filteredFooList = fooList.Where(f => f.ID.EqualOrNull(fooFilter.ID) && f.Description.EqualOrNull(fooFilter.Description) && f.Location.EqualOrNull(fooFilter.Location));

如果你想要一些真正通用的东西(例如,不依赖于知道字段名称),你需要进入反思世界。

答案 3 :(得分:0)

通过查看您的预期输出,您似乎希望过滤fooList,以便获得与Location对象具有相同fooFilter的所有项目。如果那就是你要问的,你可以这样做:

List<Foo> filteredFooList = fooList.Where(item => item.Location == fooFilter.Location);

答案 4 :(得分:0)

我最近通过使用.net中主要使用Expression类的输入对象动态构建lambda查询来解决一个非常类似的问题。如果你对你的情况感兴趣,我可以写出一个解决方案,因为已经接受了答案,但指出了可能的替代方案,因此要小心谨慎。