2013-01-11 37 views
7

我有一個IQuerable<object> source對象,必須從中得到類似的東西(但使用反射)。使用反射來創建lambda表達式,如x => new {..}

source.Select(t => new SelectListItem { Name = t.Name, Value = t.Id }) 

我該怎麼做,或者我可以在哪裏找到構建這種表達樹的參考。

感謝

+0

如果您知道您可以使用的類型Enumerable.Cast:http://msdn.microsoft.com/en-us/library/bb341406.aspx –

+0

它是將元素轉換爲'dynamic'的選項嗎? – Douglas

+0

動態聽起來比反射更好。使用反射看起來很尷尬。 Wy不能使用符合像INameValuePair這樣的接口的東西嗎? – mathk

回答

12

您可以使用該System.Linq.Expressions命名空間(MSDN

在你的情況Expression S,它會是這個樣子:

var source = typeof(Source); 
var target = typeof(SelectListItem); 

var t = Expression.Parameter(source, "t"); 

var sourceName = Expression.MakeMemberAccess(t, source.GetProperty("Name")); 
var sourceId = Expression.MakeMemberAccess(t, source.GetProperty("Id")); 

var assignName = Expression.Bind(target.GetProperty("Name"), sourceName); 
var assignValue = Expression.Bind(target.GetProperty("Value"), sourceId); 
var targetNew = Expression.New(target); 
var init = Expression.MemberInit(targetNew, assignName, assignValue); 

var lambda = 
    (Expression<Func<Source,SelectListItem>>) Expression.Lambda(init, t); 

的,你可以使用它像這樣:

IQueryable<Source> list = ... 

List<SelectListItem> items = list.Select(lambda).ToList(); 
0

對於在運行時期間知道什麼類型信息(如果有)有點不清楚。捎帶上尼古拉斯巴特勒的答案(因爲它被接受)讓我們假設你將「知道」源類型(即什麼是IQueryable源中的T類型),並且你將「知道」目標類型(返回的項目類型從IQueryable.Select擴展方法)。當我說「知道」時,我的意思是它可以在運行時被發現,而不需要動態性,反射,後期綁定等。否則,只有源和目標類型具有這些匹配名稱的屬性時,他的解決方案纔會起作用(即「名稱/ ID」&「名稱/值」)。

鑑於此,有一個非常簡單的解決方案,而無需手動構建您的lambda表達式...

解決方案: 首先讓定義這些2種類型的只是讓我們知道我們正在處理。我只能這樣做,因爲我不知道你用的是什麼類型的,所以這些都是真正爲你實際使用的是什麼佔位符,所以這是沒有必要爲您的解決方案,只是爲了演示/示例目的:

//this is whatever your source item type is (t) 
public class NameIdPair 
{ 
    public string Name { get; set; } 

    public string Id { get; set; } 
} 

//this is whatever the SelectListItem type is you're using 
public class SelectListItem 
{ 
    public string Name { get; set; } 

    public string Value { get; set; } 
} 

接下來讓我們用2個方法定義一個簡單的靜態類。一種方法將創建lambda表達式和其他方法轉換,並選擇源(IQueryable的),到了IEnumerable:

public static class QueryableExtensions 
{ 
    public static IEnumerable<TItem> Select<TSource, TItem>(this IQueryable<TSource> source) 
     where TSource : NameIdPair 
     where TItem : SelectListItem, new() 
    { 
     if (source == null) throw new ArgumentNullException("source"); 

     return source.Select(CreateLambda<TSource, TItem>()); 
    } 

    public static Expression<Func<TSource, TItem>> CreateLambda<TSource, TItem>() 
     where TSource : NameIdPair 
     where TItem : SelectListItem, new() 
    { 

     return (t) => new TItem { Name = t.Name, Value = t.Id }; 
    } 
} 

用法:

//create an instance of an IQueryable<T> for demo purposes 
var source = new[] 
{ 
    new NameIdPair {Name = "test1_name", Id = "test1_Id"}, 
    new NameIdPair {Name = "test2_name", Id = "test2_Id"} 
}.AsQueryable(); 

//you can call the "Select" extension method to select the queryable into an enum. 
var enumerable = source.Select<NameIdPair, SelectListItem>(); 
//'enumerable' is an IEnumerable<SelectListItem> instance 

//or if you just want the lambda expression... 
var lambda = QueryableExtensions.CreateLambda<NameIdPair, SelectListItem>(); 

//lambda.ToString() returns "t => new SelectListItem() {Name = t.Name, Value = t.Id}"; 

所以你去。不知道這是你正在尋找,還是它符合你的需求。希望有人會覺得它有用。

相關問題