2015-06-18 75 views
5

我必須創建一個方法來從指定類型的集合中選擇firts屬性。在泛型方法中僅設置第二個參數類型

我創建了這樣的方法(我已刪除了簡潔某些部分):

public static IQueryable<TResult> SelectFirstPropertyWithType<T, TResult>(this IQueryable<T> source) 
{ 
    // Get the first property which has the TResult type 
    var propertyName = typeof(T).GetProperties() 
     .Where(x => x.PropertyType == typeof(TResult)) 
     .Select(x => x.Name) 
     .FirstOrDefault(); 

    var parameter = Expression.Parameter(typeof(T)); 
    var body = Expression.Convert(Expression.PropertyOrField(parameter, propertyName), typeof(TResult)); 
    var expression = Expression.Lambda<Func<T, TResult>>(body, parameter); 

    return source.Select(expression); 
} 

而且我可以調用此方法爲:

List<Person> personList = new List<Person>(); 

// .. initialize personList 

personList.AsQueryable() 
      .SelectFirstPropertyWithType<Person, int>() 
      .ToList(); 

,一切工作正常。

但是,我不想將第一個參數類型設置爲Person,因爲編譯器可以從集合的源中推斷出這個參數類型。有什麼辦法來調用方法類似:

.SelectFirstPropertyWithType<int>()

的問題是我需要我的方法裏面T參數,我不希望在運行時反射創建Func

謝謝。

+0

有關於這個很多類似的問題。答案很簡單 - 你不能做那樣的事情。編譯器可以推斷所有類型或沒有。 –

回答

2

C#泛型簡單地不允許您指定類型參數的子集。這是全部或沒有。

解決此問題的方法是編寫流暢的界面。您將此操作分解爲一系列方法。

public class FirstPropertyWithTypeSelector<T> 
{ 
    private readonly IQueryable<T> _source; 

    public FirstPropertyWithTypeSelector(IQueryable<T> source) 
    { 
     _source = source; 
    } 

    public IQueryable<TResult> OfType<TResult>() 
    { 
     // Get the first property which has the TResult type 
      var propertyName = typeof(T).GetProperties() 
      .Where(x => x.PropertyType == typeof(TResult)) 
      .Select(x => x.Name) 
      .FirstOrDefault(); 
     var parameter = Expression.Parameter(typeof(T)); 
     var body = Expression.Convert(Expression.PropertyOrField(parameter, propertyName), typeof(TResult)); 
      var expression = Expression.Lambda<Func<T, TResult>>(body, parameter); 
     return _source.Select(expression); 
    } 
} 

public static FirstPropertyWithTypeSelector<T> SelectFirstProperty(this IQueryable<T> source) 
{ 
    return new FirstPropertyWithTypeSelector<T>(source); 
} 

現在,您可以撥打:

personList.AsQueryable() 
     .SelectFirstProperty().OfType<int>() 
     .ToList(); 
+0

這是否將與實體框架中的'IQueryable '一起實施? – Dennis

+0

@丹尼斯 - 這應該可以在任何提供IQueryable實現的框架上工作。 –

+0

我確實很喜歡這種方法。但是,您必須用'FirstPropertyWithTypeSelector ' –

3

不。編譯器應該能夠推斷出所有的類型參數。如果它不能,它會要求你指定它們全部。

編譯器不能告訴你它可以推斷出第一個或第二個,所以它不是具有非確定性編譯應用程序,而只是中斷。

+0

感謝您的回答。 –