2015-06-18 15 views
5

Tôi phải tạo phương thức để chọn thuộc tính firts từ bộ sưu tập với loại được chỉ định.Chỉ đặt loại đối số thứ hai theo phương thức chung

Tôi đã tạo ra phương pháp như thế này (tôi đã xóa một số phụ tùng cho các ngắn gọn):

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

Và tôi có thể gọi phương pháp này như:

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

// .. initialize personList 

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

Tất cả mọi thứ hoạt động tốt.

Nhưng, tôi không muốn đặt loại đối số đầu tiên là Person, vì trình biên dịch có thể suy ra loại đối số này từ nguồn của bộ sưu tập. Có cách nào để gọi phương thức như thế:

.SelectFirstPropertyWithType<int>()

Vấn đề là tôi cần T tham số bên trong phương pháp của tôi, và tôi không muốn tạo Func với sự phản ánh trong thời gian chạy.

Cảm ơn.

+0

Có nhiều câu hỏi tương tự về vấn đề này. Câu trả lời đơn giản - bạn không thể làm điều gì đó như thế. Trình biên dịch có thể suy ra tất cả các loại hoặc không có –

Trả lời

2

C# Generics đơn giản không cho phép bạn chỉ định một tập con của các tham số kiểu. Đó là tất cả hoặc không có gì.

Cách để giải quyết vấn đề này là viết giao diện thông thạo. Bạn phá vỡ hoạt động này thành một chuỗi các phương pháp.

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

Bây giờ bạn có thể gọi:

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

Điều này có hoạt động với việc triển khai 'IQueryable 'từ Khung thực thể không? – Dennis

+0

@ Dennis - Điều này sẽ hoạt động trên bất kỳ khung công tác nào cung cấp triển khai IQueryable . –

+0

Tôi thực sự thích cách tiếp cận này. Tuy nhiên, bạn phải thay thế 'IQueryable ' trong phương thức mở rộng bằng 'FirstPropertyWithTypeSelector ' –

3

No. Trình biên dịch có thể suy ra tất cả thông số loại. Nếu không, nó sẽ yêu cầu bạn chỉ định tất cả chúng.

Trình biên dịch không thể cho bạn biết nó có thể suy ra đầu tiên hoặc thứ hai, vì vậy thay vì có một ứng dụng biên dịch không xác định, nó chỉ phá vỡ.

+0

Cảm ơn câu trả lời. –

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