2017-12-12 2 views
4

LINQ select 문 내부에서 변수를 사용하려고합니다.LINQ 이름으로 속성 선택

다음은 현재 내가하고있는 일례입니다.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using Faker; 

namespace ConsoleTesting 
{ 
internal class Program 
{ 
    private static void Main(string[] args) 
    { 
     List<Person> listOfPersons = new List<Person> 
     { 
      new Person(), 
      new Person(), 
      new Person(), 
      new Person(), 
      new Person(), 
      new Person(), 
      new Person(), 
      new Person(), 
      new Person(), 
      new Person(), 
      new Person() 
     }; 

     var firstNames = Person.GetListOfAFirstNames(listOfPersons); 

     foreach (var item in listOfPersons) 
     { 
      Console.WriteLine(item); 
     } 

     Console.WriteLine(); 
     Console.ReadKey(); 
    } 


    public class Person 
    { 
     public string City { get; set; } 
     public string CountryName { get; set; } 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 

     public Person() 
     { 
      FirstName = NameFaker.Name(); 
      LastName = NameFaker.LastName(); 
      City = LocationFaker.City(); 
      CountryName = LocationFaker.Country(); 
     } 

     public static List<string> GetListOfAFirstNames(IEnumerable<Person> listOfPersons) 
     { 
      return listOfPersons.Select(x => x.FirstName).Distinct().OrderBy(x => x).ToList(); 
     } 

     public static List<string> GetListOfCities(IEnumerable<Person> listOfPersons) 
     { 
      return listOfPersons.Select(x => x.FirstName).Distinct().OrderBy(x => x).ToList(); 
     } 

     public static List<string> GetListOfCountries(IEnumerable<Person> listOfPersons) 
     { 
      return listOfPersons.Select(x => x.FirstName).Distinct().OrderBy(x => x).ToList(); 
     } 

     public static List<string> GetListOfLastNames(IEnumerable<Person> listOfPersons) 
     { 
      return listOfPersons.Select(x => x.FirstName).Distinct().OrderBy(x => x).ToList(); 
     } 
    } 
} 
} 

I합니다 ... GetListOf와 매우 건조하지 코드가 방법

내가이

public static List<string> GetListOfProperty(
IEnumerable<Person> listOfPersons, string property) 
     { 
      return listOfPersons.Select(x =>x.property).Distinct().OrderBy(x=> x).ToList(); 
     } 

같은 것을 할 수 있어야하지만이 유 효하지 않습니다 같은 느낌 암호. 키가 Func을 만드는 것과 관련이 있다고 생각합니다.

이것이 답변 인 경우 어떻게합니까?

여기 refelection을 사용하는 두 번째 시도가 있습니다. 그러나 이것은 또한 아무 것도 아닙니다.

 public static List<string> GetListOfProperty(IEnumerable<Person> 
listOfPersons, string property) 
     { 
      Person person = new Person(); 
      Type t = person.GetType(); 
      PropertyInfo prop = t.GetProperty(property); 
      return listOfPersons.Select(prop).Distinct().OrderBy(x => 
x).ToList(); 
} 

은 내가 원기 회복이 데드 엔드/훈제 청어 수 있습니다 생각하지만 난 어쨌든 내 작품을 보여줄 거라 생각 했어요.

참고 샘플 코드가 단순화되었지만 datalist을 AJAX를 통해 채우는 데 사용되어 자동 완성 경험을 생성합니다. 그 객체는 20 개 이상의 속성을 가지고 있으며 20 개 이상의 메소드를 작성하여 완료 할 수 있지만 이것을 완료하려면 DRY 방법이 있어야한다고 생각합니다. 또한이 한 가지 방법을 사용하면 컨트롤러 동작을 한꺼번에 정리할 수도 있습니다.

질문 : 코드의 첫 번째 섹션을 감안할 때

이 하나의 방법으로 그 유사한 방법 SELECT 문에 일부 개체를 전달 살 추상에 방법이 ???

감사합니다.

+0

당신은 코드를 보여주는뿐만 아니라 단어의 질문을 진술 수 있을까요? – Crowcoder

+0

DV GetProperty()를 호출하고 여기에 MSDN 설명서를 읽지 않고 도움을 청합니다. 귀하의 대답은 문서에 있습니다. –

+2

@Crowcoder 이것은 속성의 이름이 주어진 문자열을 속성의 값으로 선택하려고하는 또 다른 것입니다. –

답변

3

당신은 손으로

.Select(x =>x.property). 

를 구축해야합니다.

var x = Expression.Parameter(typeof(Person), "x"); 
var body = Expression.PropertyOrField(x, property); 
var lambda = Expression.Lambda<Func<Person,string>>(body, x); 

는 그 다음 Select 위가된다 : LINQ에 대한

.Select(lambda). 

(

을 기반으로 당신이 항상 동일한 유형 ( string)가 될 것으로 예상하기 때문에 다행히, 그것은 까다로운 것이 아니다 IQueyable<T>) 또는 IEnumerable<T>에 기초 LINQ위한
.Select(lambda.Compile()). 

(

).

property으로 최종 양식을 캐싱하기 위해 수행 할 수있는 모든 작업이 유용 할 것입니다.

public static List<string> GetListOfProperty(IEnumerable<Person> 
    listOfPersons, string property) 
{ 
    Type t = typeof(Person);   
    PropertyInfo prop = t.GetProperty(property); 
    return listOfPersons 
     .Select(person => (string)prop.GetValue(person)) 
     .Distinct() 
     .OrderBy(x => x) 
     .ToList(); 

}

typeof가 내장 된 C#의 연산자 당신에게 유형의 이름을 "통과"수와이다 : 당신의 예에서

+0

그래서 나는 반향과 함께 올바른 길을 가고 있었습니까? – WizardHammer

+0

@WizardHammer 가능성이 있습니다 - 당신이 원한다면 리플렉션을 통해서도 할 수 있습니다 - JamesFaix의 대답은'GetValue'를 사용하는 방법을 보여줍니다 - 당신은 또한 (지금 IDE에 없습니다) : var func = Func ) Delegate.CreateDelegate (typeof (Func ), null, prop.GetGetMethod());''func'을'Select'에 전달합니다. –

+0

Marc 지금 코드하십시오. 나는 당신과 JamesFaix의 대답 사이의 성취에 대해 궁금합니다. – WizardHammer

2

, 나는 당신이 원하는 것은이 생각 해당 인스턴스 Type을 반환합니다.런타임이 아닌 컴파일 타임에 작동하므로 정상적인 기능처럼 작동하지 않습니다.

PropertyInfo에는 개체 매개 변수를 사용하는 GetValue 메서드가 있습니다. 객체는 속성 값을 가져올 유형의 인스턴스입니다. static 속성을 타겟팅하려는 경우 해당 매개 변수에 null을 사용하십시오.

GetValueobject을 반환합니다. 실제 유형으로 캐스팅해야합니다. 당신이 재산의 모든 종류의 작업을 대신 string 하드 코딩의이 일반적인 확인하려면

string Foo(Person person) { ... }

:

person => (string)prop.GetValue(person)

는이 같은 서명을 가진 람 바어의 표현이다.

public static List<T> GetListOfProperty<T>(IEnumerable<Person> 
    listOfPersons, string property) 
{ 
    Type t = typeof(Person);   
    PropertyInfo prop = t.GetProperty(property); 
    return listOfPersons 
     .Select(person => (T)prop.GetValue(person)) 
     .Distinct() 
     .OrderBy(x => x) 
     .ToList(); 
} 
+0

이 코드는 @Marc Gravell보다 더 잘 이해합니다. 제 경우에는 항상 문자열이 될 것입니다. – WizardHammer

1

당신은 반사와 함께 할 수 있어야합니다. 나는 비슷한 것을 사용한다.

은 그냥 반성이 시도 변경 :

public static List<string> GetListOfValues(IEnumerable<Person> listOfPersons, string propertyName) 
{ 
    var ret = new List<string>(); 

    PropertyInfo prop = typeof(Person).GetProperty(propertyName); 
    if (prop != null) 
     ret = listOfPersons.Select(p => prop.GetValue(p).ToString()).Distinct().OrderBy(x => x).ToList(); 

    return ret; 
} 

나는 그것이 도움이되기를 바랍니다.

그것은 C#을 기반으로 6

3

내가 반사와 하드 코딩 된 문자열 가능한 멀리 것 ...

어떻게 T의 함수 선택기를 받아들이는 확장 메서드 정의에 대한, 당신이 문자열 속성 옆에

public static List<T> Query<T>(this IEnumerable<Person> instance, Func<Person, T> selector) 
{ 
    return instance 
     .Select(selector) 
     .Distinct() 
     .OrderBy(x => x) 
     .ToList(); 
} 

를 다른 유형을 처리하고 상상할 수 있도록 일반의 ID 속성을 가지고있는 사람 클래스를 가지고 이미 노출 그 외에 전자 INT

public class Person 
{ 
    public int Id { get; set; } 
    public string City { get; set; } 
    public string CountryName { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
} 

당신이 당신이 정말로 하드 코딩 된 문자열을해야 할 것 같다으로 형태 보증 된 람다 선택기

var ids = listOfPersons.Query(p => p.Id); 
var firstNames = listOfPersons.Query(p => p.FirstName); 
var lastNames = listOfPersons.Query(p => p.LastName); 
var cityNames = listOfPersons.Query(p => p.City); 
var countryNames = listOfPersons.Query(p => p.CountryName); 

와 결과를 가져되어 편집

을 할 필요 속성 입력으로, 어떤 역 동성을 버리고 결정론의 비트를 사용하는 방법은 무엇입니까?

public static List<string> Query(this IEnumerable<Person> instance, string property) 
{ 
    switch (property) 
    { 
     case "ids": return instance.Query(p => p.Id.ToString()); 
     case "firstName": return instance.Query(p => p.FirstName); 
     case "lastName": return instance.Query(p => p.LastName); 
     case "countryName": return instance.Query(p => p.CountryName); 
     case "cityName": return instance.Query(p => p.City); 
     default: throw new Exception($"{property} is not supported"); 
    } 
} 

과 같은 원하는 결과를 액세스

var cityNames = listOfPersons.Query("cityName"); 
+0

linqpad ready gist 전체 내용보기 https://gist.github.com/dandohotaru/3c2a2b4eb1a07c43cb66c7044ed3f7ce –

+0

+1 이러한 이름이 외부 소스 (예 : 데이터베이스)에서 오는 것이 아니라면 반영이나 '표현'이 필요 없습니다. Luke, 'Func'을 사용하십시오. –

+0

필자의 예 (간소화 된 내용)와 관련하여 이에 동의합니다. 그러나 실제로, 이것은 원하는 목록 유형을받는 Ajax 호출에 의해 유도됩니다. Json 객체를 반환합니다. 다음은 @Marc Gravell의 예제입니다. – WizardHammer