如何使用lambda表达式按字符串属性名称进行选择查询?

4
我想使用lambda select进行查询,如下所示:
public class Foo{
   public int Id {get;set;}
   public string Name {get;set;}
   public string Surname {get;set;}
}

var list = new List<Foo>();
var temp = list.Select(x=> x("Name"),("Surname"));

属性名需要以字符串形式发送, 我不知道如何使用,我只是举了一个例子。 有可能吗?
Foo list :
1  A B
2  C D
3  E F
4  G H

我不知道泛型列表的类型,但我有诸如“Name”、“Surname”之类的属性名称。

我希望它像下面这样:

Result :

A B
C D
E F
G H

尝试使用动态LINQ库。希望能解决您的问题。请查看以下链接http://www.c-sharpcorner.com/UploadFile/deveshomar/dynamic-linq-library-in-C-Sharp/。 - Simranjeet Singh
我有一些属性名称,但不知道通用列表的类型。我想通过属性名称来筛选列表,而不是值。 - Sinan AKYAZICI
我展示了两个例子,分别执行了两个不同的操作 - 一个是过滤,另一个是创建一个仅有姓名和姓氏两个属性的匿名对象列表。 - Mez
问题:var list = new List<Foo>(); - 这意味着您在编译时知道类型并可以直接访问其属性。我想您的意思是 var list = new List<T>(); - John Woo
我提供了一个示例,但不太清楚,实际上 var list = new List<T>() 是正确的。 - Sinan AKYAZICI
显示剩余2条评论
4个回答

4
以下代码片段展示了两种情况。一种是对列表进行过滤,另一种是创建一个只包含姓名和姓氏的匿名对象的新列表。
List<Foo> list = new List<Foo>();

var newList = list.Select(x=> new {  
                    AnyName1 = x.Name,
                    AnyName2 = x.Surname
                }); 

var filteredList = list.Select(x => x.Name == "FilteredName" && x.Surname == "FilteredSurname");

var filteredListByLinq = from cust in list
                             where cust.Name == "Name" && cust.Surname == "Surname"
                             select cust;

var filteredByUsingReflection = list.Select(c => c.GetType().GetProperty("Name").GetValue(c, null));

我没有说属性值,我说的是属性名称,我不知道泛型列表的类型,我怎么能使用x.Name或x.Surname? - Sinan AKYAZICI
所以你想要过滤x.Name对吧?那么你可以使用第二个和第三个选项中的任何一个。除非我误解了你的意思? - Mez
他似乎需要过滤,但我也不确定。你知道的,需求一直在改变,这是软件开发中唯一的常数。 - Patrice Gahide
我在我的回答中还包括了使用linq to sql进行过滤,但似乎并没有回答问题。OP特别想使用“Select” - 但是嗯,我必须同意您的要求。 - Mez
@sinanakyazici,当时你处理好了吗?为了帮助其他用户,请选择答案,以便其他人可以参考。 - Mez
显示剩余5条评论

1

接口

如果您可以访问相关类型,并且始终想要访问相同的属性,则最好的选择是使这些类型实现相同的接口:

public interface INamable
{
  string Name { get; }
  string Surname { get; }
}

public class Foo : INamable
{
  public int Id { get; set; }
  public string Name { get; set; }
  public string Surname { get; set; }
}

这将保持类型安全,并启用像这样的查询:
public void ExtractUsingInterface<T>(IEnumerable<T> list) where T : INamable
{
  var names = list.Select(o => new { Name = o.Name, Surname = o.Surname });

  foreach (var n in names)
  {
    Console.WriteLine(n.Name + " " + n.Surname);
  }
}

如果由于某种原因,您无法更改原始类型,则有两个其他选项。

反射

第一个选项是反射。这是Mez的答案,我将其用匿名类型重新表述,就像在先前的解决方案中一样(不确定您需要什么):

public void ExtractUsingReflection<T>(IEnumerable<T> list)
{
  var names = list.Select(o => new
                               {
                                 Name = GetStringValue(o, "Name"),
                                 Surname = GetStringValue(o, "Surname")
                               });
  foreach (var n in names)
  {
    Console.WriteLine(n.Name + " " + n.Surname);
  }
}

private static string GetStringValue<T>(T obj, string propName)
{
  return obj.GetType().GetProperty(propName).GetValue(obj, null) as string;
}

动态

第二个使用了动态:

public void ExtractUsingDynamic(IEnumerable list)
{
  var dynamicList = list.Cast<dynamic>();
  var names = dynamicList.Select(d => new
                                      {
                                        Name = d.Name,
                                        Surname = d.Surname
                                      });
  foreach (var n in names)
  {
    Console.WriteLine(n.Name + " " + n.Surname);
  }
}

有了这个,以下代码:

With that in place, the following code:

IEnumerable<INamable> list = new List<Foo>
                             {
                               new Foo() {Id = 1, Name = "FooName1", Surname = "FooSurname1"},
                               new Foo() {Id = 2, Name = "FooName2", Surname = "FooSurname2"}
                             };
ExtractUsingInterface(list);
// IEnumerable<object> list... will be fine for both solutions below
ExtractUsingReflection(list);
ExtractUsingDynamic(list);

将会产生预期的输出:
FooName1 FooSurname1
FooName2 FooSurname2
FooName1 FooSurname1
FooName2 FooSurname2
FooName1 FooSurname1
FooName2 FooSurname2

我相信你可以调整它并达到你想要的目标。


0
var temp = list.Select(x => x.Name == "Name" && x.Surname == "Surname");

0
var temp = list.Select(x => new {Name = x.Name, Surname = x.Surname});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接