我有一個IQuerable<object> source
對象,必須從中得到類似的東西(但使用反射)。使用反射來創建lambda表達式,如x => new {..}
source.Select(t => new SelectListItem { Name = t.Name, Value = t.Id })
我該怎麼做,或者我可以在哪裏找到構建這種表達樹的參考。
感謝
我有一個IQuerable<object> source
對象,必須從中得到類似的東西(但使用反射)。使用反射來創建lambda表達式,如x => new {..}
source.Select(t => new SelectListItem { Name = t.Name, Value = t.Id })
我該怎麼做,或者我可以在哪裏找到構建這種表達樹的參考。
感謝
您可以使用該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();
對於在運行時期間知道什麼類型信息(如果有)有點不清楚。捎帶上尼古拉斯巴特勒的答案(因爲它被接受)讓我們假設你將「知道」源類型(即什麼是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}";
所以你去。不知道這是你正在尋找,還是它符合你的需求。希望有人會覺得它有用。
如果您知道您可以使用的類型Enumerable.Cast:http://msdn.microsoft.com/en-us/library/bb341406.aspx –
它是將元素轉換爲'dynamic'的選項嗎? – Douglas
動態聽起來比反射更好。使用反射看起來很尷尬。 Wy不能使用符合像INameValuePair這樣的接口的東西嗎? – mathk