Câu hỏi này là sự tiếp nối của câu hỏi này đây .Nếu có ai thắc mắc tại sao tôi cần phải làm điều gì đó như thế này thì bạn có thể tìm lý do trong câu hỏi đó. Nó không quan trọng, thực sự.
Tôi cần một phương pháp như thế này:
biểu thức ảo công khai<>> UpdateCriterion()
{
// điều này không hiệu quả vì trình biên dịch không biết liệu T có Id & CompanyId hay không
return e => new { e.Id, e.CompanyId };
}
Vấn đề là,T
Không có gì tôi có thể sử dụng để trích xuất từ Id
Và Mã công ty
Loại siêu hạng thì tôi phải làm cho nó năng động. Nhờ câu trả lời cho câu hỏi được tham chiếu đó, tôi đã xây dựng và sử dụng thành công phương pháp này cho một thuộc tính (e => e.Id
), nhưng tôi gặp sự cố khi triển khai nó cho hai thuộc tính. Chỉ để hiển thị, giải pháp một lĩnh vực là:
biểu thức ảo công khai<>> UpdateCriterion()
{
var param = Expression.Parameter(typeof(T));
var body = Expression.Convert(Expression.Property(param, "ID"), typeof(object));
return Expression.Lambda<>>(body, param);
}
Tôi đã gặp khó khăn với vấn đề này hơn 6 giờ... Vậy làm cách nào để khắc phục vấn đề này?
Phần thân của Lamba này là MemerInitExpression.
Đây là phần dễ dàng. Vấn đề lớn hơn ở đây là bạn đang sử dụng các loại ẩn danh trong Lambda của mình.
Biểu thức<>> exp;
exp = p => new { p.LanguageId, p.TextId};
Nếu bạn sử dụng AnonymousType như vậy, trình biên dịch sẽ kiểm tra mã của bạn, phát hiện khai báo AnonymousType và tạo một loại như vậy một cách nhanh chóng.
lớp công khai f__AnonymousType0
{
public int LanguageId { được đặt;
public int TextId { được đặt;
}
Sau đó thay đổi lambda của bạn thành cái này.
exp = p => new f__AnonymousType0 { LanguageId = p.LanguageId, TextId = p.TextId };
Vì bạn muốn tạo lambda trong thời gian chạy nên loại f__AnonymousType0 mà MemberInitExpression yêu cầu không tồn tại.
Vì bạn cần một loại thực tế để tạo biểu thức này nên bạn có hai tùy chọn.
1 - Viết một số lớp chung, chẳng hạn như lớp Tuple của .NET Framework. Đối với lõi, giải pháp này được giới hạn ở số lượng thuộc tính tối đa.
Ưu điểm: Dễ tạo và sử dụng – Nhược điểm: Số lượng thuộc tính hạn chế.
lớp công khai KeyTuple
{
công khai T1 Item1 { được;
công khai T2 Item2 { được đặt;
}
lớp công khai KeyTuple
{
công khai T1 Item1 { được;
công khai T2 Item2 { được đặt;
công khai T3 Item3 { được;
}
lớp công khai KeyTuple
lớp công khai KeyTuple
lớp công khai KeyTuple
lớp công khai KeyTuple
2 - Bạn có thể sử dụng Reflection.Emit và tạo một loại khi chạy http://www.codeproject.com/Articles/121568/Dynamic-Type-Using-Reflection-Emit
Ưu điểm: Không giới hạn số lượng thuộc tính – Nhược điểm: Phức tạp
Khi bạn có một loại, bạn có thể sử dụng API cây biểu thức mà bạn đã biết để tạo lambda
var key = new[] { "LanguageId", "TextId" };
var param = Expression.Parameter(typeof(TranslationText));
var Properties = key.Select(p => Expression.Property(param, p)).ToList();
var keyTupleType = typeof(KeyTuple<,>).Assembly.GetType(string.Format("AnonymousTypeExpression.KeyTuple`{0}",keys.Count()));
keyTupleType = keyTupleType.MakeGenericType(properties.Select(p => p.Type).ToArray());
var Bindings = Properties.Select((p,i) => Expression.Bind(keyTupleType.GetProperty(string.Format("Item{0}",i + 1)),p)).ToArray();
var body = Expression.MemberInit(Expression.New(keyTupleType), liên kết);
var result= Expression.Lambda<>>(body, param);
Điều này sẽ tạo ra một biểu thức trông như thế này
exp = p => new KeyTuple { Item1 = p.LanguageId, Item2 = p.TextId };
Tôi là một lập trình viên xuất sắc, rất giỏi!