2013-08-19 37 views
5

Tôi đang cố gắng để gọi một chức năng trong một tuyên bố chọn LINQ năng động, nhưng im nhận được lỗi:Gọi hàm trong LINQ động

No property or field 'A' exists in type 'Tuple2' 

Ví dụ mã:

void Main() 
{ 
    var a = new Tuple<int, int>(1,1); 
    var b = new[]{ a }; 
    var q = b.AsQueryable().Select("A.Test(it.Item1)"); 

    q.Dump(); 
} 

public static class A 
{ 
    public static int Test(int i) 
    { 
     return i++; 
    } 
} 

Làm thế nào tôi nên thay đổi của tôi mã để làm việc này?

Nếu tôi gọi hàm dựng sẵn Convert.ToInt32 chẳng hạn như nó hoạt động tốt.

var q = b.AsQueryable().Select("Convert.ToInt32(it.Item1)"); 

Ngoài ra làm cách nào để truyền thuộc tính bằng LINQ động?

var q = b.AsQueryable().Select("((float)it.Item1)"); 
+0

Cú pháp nào là nơi bạn sử dụng một chuỗi trong phương thức 'Enumerable.Select'? –

+0

@Bob. Được viết trong các thẻ: dynamic-linq – xanatos

Trả lời

8

Tôi sẽ nói rằng dynamic-linq không đủ mạnh để làm những việc này. Có vẻ cho các phương pháp duy nhất trong các đối tượng nhất định và một số các lớp học đặc biệt: Math, Convert, các loại cơ sở khác nhau (int, float, string ...), Guid, Timespan, DateTime

Danh mục các loại rõ ràng là có thể nhìn thấy nếu bạn sử dụng ilspy/reflector trên tập tin. Họ đang ở trong System.Linq.Dynamic.ExpressionParser.predefinedTypes.

Bây giờ, rõ ràng tôi có thể sai, nhưng hoạt động này: .Select("Guid.NewGuid().ToString()").Cast<string>().ToArray()

cho thấy rằng nó khá có thể xảy ra rằng đó là "đúng" danh sách.

Có một bài viết ở đây về cách sửa đổi động LINQ nếu bạn quan tâm http://www.krizzcode.com/2012/01/extending-dynamiclinq-language.html

Bây giờ, một người đàn ông thông minh sẽ mất nguồn gốc của LINQ năng động và đơn giản là mở rộng mảng mà ... Nhưng ở đây không có người đàn ông thông minh ...Chỉ có các lập trình viên muốn có máu! Máu nhưng đặc biệt là nội bộ!

var type = typeof(DynamicQueryable).Assembly.GetType("System.Linq.Dynamic.ExpressionParser"); 

FieldInfo field = type.GetField("predefinedTypes", BindingFlags.Static | BindingFlags.NonPublic); 

Type[] predefinedTypes = (Type[])field.GetValue(null); 

Array.Resize(ref predefinedTypes, predefinedTypes.Length + 1); 
predefinedTypes[predefinedTypes.Length - 1] = typeof(A); // Your type 

field.SetValue(null, predefinedTypes); 

Làm điều này (với các loại bạn muốn) TRƯỚC cuộc gọi đầu tiên Dynamic LINQ (vì sau khi người đầu tiên gọi các phương pháp/tài sản của các loại được lưu trữ)

Giải thích: chúng tôi sử dụng phản ánh thêm đối tượng của chúng tôi cho "danh sách đặc biệt" này.

+0

Thay vì trả lời nếu nó có thể là một gợi ý .... – andy

+1

@andy Câu trả lời là không thể vẫn còn là một câu trả lời – xanatos

+0

Cảm ơn các con trỏ @xanatos – Magnus

0
var b = new[]{ a }; 

Mảng trên là không biết những gì loại của mảng, và nó không phải là loại an toàn?

giá trị của bạn được giao nhiệm vụ trong kiểu dữ liệu biến thể vì vậy nó không giá trị số nguyên (Tôi nghĩ rằng giá trị string), khi bạn nhận được các giá trị này trong truy vấn của bạn phải cần phải convert.toint32() vì kiểu lớp tham số dữ liệu của bạn là số nguyên

Vui lòng thử nó

var b = new **int**[]{ a }; 

thay vì var b = new[]{ a };

các gợi ý quan trọng là ở đây (in đậm):

No property or field 'xxx' exists in **type** 'xxx' 

Và hãy nhìn này để thảo luận trước đó:

Dynamic Linq - no property or field exists in type 'datarow'

0

tôi có thể bị nhầm lẫn nhưng cú pháp của bạn nhờ đó mà bạn đang sử dụng một chuỗi trong Select s của bạn không biên dịch cho tôi. Cú pháp sau hoạt động:

var q = b.AsQueryable().Select(it => A.Test(it.Item1)); 
+1

'Lựa chọn của bạn không biên dịch cho tôi' vì OP sử dụng linq động http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part -1-using-the-linq-dynamic-query-library.aspx – I4V

+0

Ah vì vậy tôi đã nhầm lẫn :) –

0

Các công trình sau đây cho tôi:

var a = new Tuple<int, int>(1, 1); 
var b = new[] { a }; 
var q = b.AsQueryable().Select(it=>A.Test(it.Item1)); 
var q1 = b.AsQueryable().Select(it => Convert.ToInt32(it.Item1)); 
var q2 = b.AsQueryable().Select(it => (float) it.Item1); 
6

Tôi biết có đã là một câu trả lời chấp nhận về vấn đề này nhưng nó đã không làm việc cho tôi. Tôi đang sử dụng Dynamic Linq 1.1.4. Tôi muốn thực hiện một truy vấn như thế này

$.GetNewestRisk() == null 

Nơi GetNewestRisk() là phương thức công khai trên đối tượng được đại diện bởi $. Tôi tiếp tục nhận được lỗi này "Lỗi khi chạy truy vấn, phương pháp trên loại 'Bệnh nhân' không thể truy cập (tại chỉ số 2)".

Tôi tìm thấy trong mã nguồn có một đối tượng GlobalConfig cho phép một nhà cung cấp tùy chỉnh được chỉ định sẽ giữ tất cả các loại bạn có thể muốn làm việc. Đây là mã nguồn cho các nhà cung cấp tùy chỉnh:

public class CustomTypeProvider: IDynamicLinkCustomTypeProvider 
{ 
    public HashSet<Type> GetCustomTypes() 
    { 
     HashSet<Type> types = new HashSet<Type>(); 
     types.Add(typeof(Patient)); 
     types.Add(typeof(RiskFactorResult)); 
     types.Add(typeof(PatientLabResult)); 
     types.Add(typeof(PatientVital)); 
     return types; 
    } 
} 

đây là làm thế nào tôi đang sử dụng nó:

System.Linq.Dynamic.GlobalConfig.CustomTypeProvider = new CustomType(); 

Sau khi thực hiện cuộc gọi này tôi có thể gọi các phương thức trên các đối tượng bên trong của biểu thức.

+0

Tôi đã có thể điều chỉnh câu trả lời này cho System.Linq.Dynamic.Core. Nó có cùng giao diện nhưng nó cũng có ParsingConfig cho phép bạn cung cấp các kiểu cho các biểu thức riêng lẻ hơn là áp dụng các kiểu tùy chỉnh trên toàn cầu. – Kent

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