Expression
numaralı bildirimi kullanarak, özelliği uygun bir şekilde (özellik yolunu temsil eden ve Yansıma'yı kullanarak noktayla ayrılmış bir dizeyi ayrıştırma gibi olmaksızın) seçmek için kullanmak istediğinizi anlıyorum. Ancak bunu yapmak, Expression
'un açıkça beyan edilmesini gerektirir ve açık tip kullanmamız gerekir. Ne yazık ki, object
türünün, İfade'nin dönüş türü olarak kullanılamaz, çünkü daha sonra veritabanında desteklenen türlerden birine dönüştürülemez.
Burada bir çalışma olduğunu düşünüyorum. Buradaki fikir Expression<T,object>
'u Expression<T,returnType>
'a çevirecektir, burada returnType
mülkün gerçek dönüş türüdür (selector
tarafından iade edilir). Ancak Select
, her zaman tasarım zamanında returnType
anlamına gelen Expression<T,returnType>
anlamında açık bir tip gerektirir. Yani bu imkansız. Doğrudan Select
numaralı telefonu arama imkanımız yok. Bunun yerine, Select
'u çağırmak için Yansıma'yı kullanmalıyız. Geri dönüş sonucu, istediğiniz nesnelerin bir listesini almak için ToList()
'u arayabileceğiniz bir IEnumerable<object>
olarak bekleniyor.
Şimdi IQueryable<T>
için bu uzatma yöntemi kullanabilirsiniz:
public static class QExtension
{
public static IEnumerable<object> Select<T>(this IQueryable<T> source,
Expression<Func<T, object>> exp) where T : class
{
var u = exp.Body as UnaryExpression;
if(u == null) throw new ArgumentException("exp Body should be a UnaryExpression.");
//convert the Func<T,object> to Func<T, actualReturnType>
var funcType = typeof(Func<,>).MakeGenericType(source.ElementType, u.Operand.Type);
//except the funcType, the new converted lambda expression
//is almost the same with the input lambda expression.
var le = Expression.Lambda(funcType, u.Operand, exp.Parameters);
//try getting the Select method of the static class Queryable.
var sl = Expression.Call(typeof(Queryable), "Select",
new[] { source.ElementType, u.Operand.Type },
Expression.Constant(source), le).Method;
//finally invoke the Select method and get the result
//in which each element type should be the return property type
//(returned by selector)
return ((IEnumerable)sl.Invoke(null, new object[] { source, le })).Cast<object>();
}
}
Kullanımı: Ben exp.Body.Type
erişen çalıştı ve bu düşünce İlk başta
Expression<Func<Customer, object>> selector = cust => cust.CreatedOn;
IQueryable<Customer> customers = ctx.Set<Customer>();
IList<object> customerNames = customers.Select(selector).Distinct().ToList();
(tam olarak kodu olarak) iç ifadenin gerçek dönüş tipi. Ancak her nasılsa, string
özel özel durumu hariç her zaman System.Object
(özellik erişiminin dönüş türü string
olduğunda). Bu, iç ifadenin gerçek dönüş türüyle ilgili bilgilerin tamamen kaybolduğunu (veya en azından çok dikkatli bir şekilde gizlendiğini) gösterir. Bu tarz bir tasarım oldukça garip ve tamamen kabul edilemez. Neden böyle yaptığını anlamıyorum. İfadenin gerçek dönüş tipi ile ilgili bilgilere kolayca erişilmiş olmalıdır.
Sonunda 'ToList' olarak adlandırıyorsunuz, o zaman neden daha sonra bunlara itiraz etmek için DateTime'ı seçmiyorsunuz? – Hopeless
Seçici üye ifadesi çalışma zamanında oluşturulduğundan, özellik türü derleme zamanında bilinmez. Ben türünü belirlemek için yansıma kullanabilirdim, ama bu iç içe geçmiş özellikler için karmaşık olurdu – user2346738