2013-01-11 28 views
7

Tôi có một đối tượng IQuerable<object> source và phải lấy từ nó một cái gì đó như thế (nhưng sử dụng sự phản chiếu).Sử dụng sự phản chiếu để tạo ra biểu thức lambda như x => new {..}

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

Làm cách nào tôi có thể làm điều đó hoặc tôi có thể tìm tài liệu tham khảo về việc xây dựng loại cây biểu thức đó ở đâu.

Cảm ơn

+0

nếu bạn biết loại bạn có thể sử dụng Enumerable.Cast: http://msdn.microsoft.com/en-us/library/bb341406.aspx –

+0

Nó sẽ là một tùy chọn để đúc các phần tử thành 'động'? – Douglas

+0

động âm thanh một lựa chọn tốt hơn so với phản ánh. Nó trông khá vụng về để sử dụng sự phản chiếu. Wy bạn không thể sử dụng cái gì đó phù hợp với một giao diện như INameValuePair? – mathk

Trả lời

12

Bạn có thể tạo Expression s sử dụng System.Linq.Expressions namespace (MSDN)

Trong trường hợp của bạn, nó sẽ giống như thế này:

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); 

Các bạn có thể sử dụng nó như thế này :

IQueryable<Source> list = ... 

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

Một chút không rõ ràng về thông tin Loại (nếu có) được biết trong thời gian chạy. Hãy giả sử rằng bạn sẽ "biết" loại nguồn (tức là loại T trong nguồn IQueryable là gì) và bạn sẽ "biết" loại mục tiêu (loại mục được trả về) từ phương pháp mở rộng IQueryable.Select). Khi tôi nói "biết", ý tôi là nó có thể được phát hiện trong thời gian chạy mà không có động lực, phản xạ, kết buộc muộn, vv. Nếu không, giải pháp của anh ta sẽ chỉ hoạt động nếu các kiểu nguồn và đích chỉ xảy ra để có các thuộc tính với các tên phù hợp đó (nghĩa là "Tên/Id" & "Tên/Giá trị").

Vì điều này, có một giải pháp khá đơn giản mà không cần phải tự xây dựng biểu thức lambda của bạn ...

Giải pháp: Đầu tiên cho phép xác định các 2 loại chỉ để chúng tôi biết những gì chúng ta đang đối phó với. Tôi chỉ làm điều này vì tôi không biết những gì loại bạn đang sử dụng, vì vậy đây là những thực sự placeholders cho những gì bạn đang thực sự sử dụng, vì vậy đây là không cần thiết cho giải pháp của bạn, chỉ vì mục đích demo/Ví dụ:

//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; } 
} 

Tiếp theo cho phép xác định một lớp tĩnh đơn giản với 2 phương thức. Một phương pháp sẽ tạo ra các biểu thức lambda và các phương pháp khác sẽ chuyển đổi và chọn nguồn (IQueryable) vào 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 }; 
    } 
} 

Cách sử dụng:

//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}"; 

Vì vậy, có bạn đi. Không chắc chắn nếu đó là những gì bạn đang tìm kiếm, hoặc nếu nó phù hợp với nhu cầu của bạn. Hy vọng rằng ai đó sẽ thấy nó hữu ích.

Các vấn đề liên quan