2013-08-20 10 views
5

जब IQuerayble<TItem> के साथ काम कर हम Select इस तरह कॉल कर सकते हैं:अभिव्यक्ति वृक्ष में गतिशील वस्तु को तुरंत चालू और प्रारंभ कैसे करें?

query.Select(item => new { A=item.Prop1, B=item.Prop2}); 

और Select विधि उम्मीद Expression<Func<TItem,TResult>>

मैं गुमनाम लेकिन स्थिर टाइप किया वर्ग के बजाय ExpandoObject उपयोग करने के लिए की जरूरत है।

यदि यह संभव थे यह देखने के लिए की तरह होगा:

query.Select(item => dynamic new ExpandoBoject { A=item.Prop1, B=item.Prop2}); 

तो मैं अभिव्यक्ति पेड़ Expression<Func<TItem,ExpandoObject>> जहां ऑब्जेक्ट के गुणों गुमनाम प्रकार के साथ के रूप में समान तरीके से प्रारंभ कर रहे हैं का निर्माण करना चाहते हैं।
डायनामिक कार्यक्षमता केवल प्रारंभिकरण के लिए आवश्यक है, इसलिए यह ठीक है कि Func dynamic के बजाय ExpandoObject लौटाता है।

मुझे Expression.Dynamic और संबंधित बाइंडर्स के बारे में अधिक दस्तावेज नहीं मिल रहा है।


अद्यतन 1

मैं यह सब सामान आवश्यकता क्यों है?
क्योंकि मैं get primary keys चाहता हूं।
मैं इसे किसी भी इकाई प्रकार के लिए करना चाहता हूं।

मुझे पता है कि पीके लिखने वाले गुणों की सूची कैसे प्राप्त करें, लेकिन अब मुझे EntityKey पर इकाई का एक मुश्किल प्रक्षेपण करने की आवश्यकता है। खैर, इस वर्ग के समान समकक्ष हो सकता है।

var keys = context.Set<TEntity>().Where(Expression<Func<TEntity,bool>).Select(Expression<Func<TEntity,EntityKey>>); 

जैसा कि मैंने ब्लॉक युक्त टिप्पणियों lambdas में नोट अभिव्यक्ति पेड़ को नहीं बदला जा सकता तो मैं सरल नहीं शब्दकोश बनाने और इसे भर सकते हैं। अब मैं अभिव्यक्ति पेड़ शब्दार्थ इस कोड के करीब के साथ खेल रहा हूँ:

var dict = new Dictionary<string,object>(); 
dict.Add("Prop1",value1); 
dict.Add("Prop2",value2); 
return dict 

लेकिन मुझे शक है एफई ब्लॉक युक्त अभिव्यक्ति पार्स कर सकते हैं। देखने की जरूरत है।
और मैं उत्सुक हूं कि यह गतिशील वस्तुओं और अभिव्यक्ति के साथ काम करेगा। मेम्बरइनिट क्योंकि यह स्थिर वस्तुओं के साथ काम करता है।


अद्यतन 2

इकाई की रूपरेखा शब्दकोश प्रारंभ वाक्य रचना का समर्थन नहीं करता।
यह संदेश के साथ NotSupportedException फेंकता है: केवल एक तत्व के साथ प्रारंभिक आइटम सूचीबद्ध करें LINQ से इकाइयों में समर्थित हैं।


अद्यतन 3

एफई रूप में अच्छी तरह ब्लॉक भाव समर्थन नहीं करता।
NotSupportedException संदेश के साथ: टाइप 'ब्लॉक' की अज्ञात LINQ अभिव्यक्ति।

+0

आप ऐसा कुछ नहीं कर सकते: 'query.Select (item => गतिशील नया ExpandoBoject {ए = आइटम.प्रॉप 1, बी = आइटम.प्रॉप 2}); 'लिपर्ट ने इसे बताया: http: // stackoverflow। कॉम/प्रश्न/7478048/क्यों-cant-i-do-this-dynamic-x-new-expandoobject-foo-12-bar-बारह। – xanatos

+0

मुझे पता है, मैं नहीं कर सकता। यह गतिशीलता के साथ अभिव्यक्ति वृक्ष बनाने के इरादे का एक उदाहरण था। –

+0

क्या किया जा सकता है LINQ में एक अनाम प्रकार बनाते हैं और फिर, IQueryable समाप्त होने के बाद, IENumerable भाग में अज्ञात प्रकार को एक Expando ऑब्जेक्ट में कॉपी करें। स्पष्ट रूप से दोनों अभिव्यक्तियों को किसी तरह से स्वत: उत्पन्न किया जा सकता है। – xanatos

उत्तर

3

अब मैं अभिव्यक्ति पेड़ शब्दार्थ इस कोड के करीब के साथ खेल रहा हूँ:

var dict = new Dictionary<string,object>(); 
dict.Add("Prop1",value1); 
dict.Add("Prop2",value2); 
return dict; 

आप कर सकते हैं करना है कि, क्योंकि आप के रूप में की तरह एक भी अभिव्यक्ति के रूप में है कि कोड लिख सकते हैं यह:

new Dictionary<string, object> 
{ 
    { "Prop1", value1 }, 
    { "Prop2", value2 } 
}; 

और आप एक अभिव्यक्ति वृक्ष बना सकते हैं जिसमें यह अभिव्यक्ति है (जो ईएफ एस hould इस तरह संभालने में सक्षम) होना:

var addMethod = typeof(Dictionary<string, object>).GetMethod("Add"); 

var expression = Expression.Lambda<Func<Dictionary<string, object>>>(
    Expression.ListInit(
     Expression.New(typeof(Dictionary<string, object>)), 
     Expression.ElementInit(
      addMethod, 
      Expression.Constant("Prop1"), 
      value1Expression), 
     Expression.ElementInit(
      addMethod, 
      Expression.Constant("Prop2"), 
      value2Expression)), 
    itemParameterExpression); 
+0

मैं आज कोशिश करूंगा, लेकिन ईएफ ने शब्दकोश प्रारंभिक वाक्यविन्यास के बारे में शिकायत की है कि यह केवल सरल सूचियों को समझता है। –

+0

नहीं, ईएफ अपवाद फेंकता है। –

+0

@ voroninp उस स्थिति में, आप 'नया [] {Tuple.Create ("Prop1", value1), Tuple.Create ("Prop2", value2)} जैसे कुछ कोशिश कर सकते हैं। – svick

1

वर्णित बात मुश्किल है जिसका मुख्य कारण हम नहीं रन टाइम पर गतिशील रूप से गुमनाम प्रकार बना सकते हैं - वे संकलन समय पर पहले से ही ज्ञात किया जाना चाहिए। तो मेरा प्रस्ताव एक वर्ग बनाना है जिसमें मनमाना चुने गए प्रकार (टुपल के समान) के कई गुण हो सकते हैं, हालांकि हम केवल हमारे लिए महत्वपूर्ण गुणों के लिए डीबी मानों से लोड होंगे। तो हमें इस तरह की कक्षा की आवश्यकता है:

public class CustomTuple<T1, T2> 
{ 
    public T1 Item1 { get; set; } 
    public T2 Item2 { get; set; } 
} 

यदि हमें और आवश्यकता है तो हम और अधिक गुण जोड़ सकते हैं। अगर हमारे पास 5 गुणों के साथ ऐसी कक्षा होगी जिसमें इसका उपयोग करने के साथ हम अधिकतम 5 गुणों पर लोड कर सकते हैं। अब प्रक्षेपण तर्क:

Type[] parameterTypes = new Type[] { typeof(int), typeof(object) }; 
Type tupleType = typeof(CustomTuple<,>).MakeGenericType(parameterTypes); 
ParameterExpression x = Expression.Parameter(typeof(Entity)); 
NewExpression body = Expression.New(tupleType.GetConstructor(new Type[0]), new Expression[0]); 
MemberBinding binding1 = Expression.Bind(
    typeof(CustomTuple<,>).MakeGenericType(parameterTypes).GetProperty("Item1"), 
    Expression.Property(x, "Value")); 
MemberInitExpression memberInitExpression = 
    Expression.MemberInit(
     body, 
     binding1); 

Expression<Func<Entity, object>> exp = Expression.Lambda<Func<Entity, object>>(memberInitExpression, x); 
using (MyDbContext context = new MyDbContext()) 
{ 
    var list = context.Entities.Select(exp).ToList(); 
} 

ऊपर कोड से इकाई वर्ग मूल्य संपत्ति का संस्थाओं संग्रह मूल्यों चयन करता है। पैरामीटर टाइप टाइप प्रोजेक्शन से लौटाए गए पैरामीटर के प्रकार को परिभाषित करता है। अगर हम दी गई संपत्ति का उपयोग करने का इरादा नहीं रखते हैं तो हम इसे ऑब्जेक्ट प्रकार के रूप में छोड़ देते हैं। फिर हमें प्रारंभिक अभिव्यक्ति बनाने की आवश्यकता है। हम इसे विधि विधि के साथ करते हैं, हम अभिव्यक्ति द्वारा बनाए गए अभिव्यक्ति के साथ गुण मान निर्दिष्ट करते हैं। बाइंड करें और हम उन्हें अभिव्यक्ति के साथ एक साथ जोड़ते हैं। मेम्बरइनिट। हम गतिशील रूप से रनबाइम पर जितना अधिक सदस्य बाइंडिंग एक्सप्रेशन कर सकते हैं उतना ही बना सकते हैं।

+0

असल में समान विचार के साथ अपना उत्तर हटा दिया, वास्तव में, जो मैंने अंततः किया था। लेकिन मैं शून्य गुणों से शुरू किया। अनुमोदित विरासत के साथ ExpandoObject के एनालॉग बनाया गया और फिर गतिशील रूप से CodeEmit के साथ आवश्यक गुणों के साथ पूर्वजों वर्ग उत्पन्न किया। इससे मुझे सामान्य रूप से ईएफ से संस्थाओं के पीके पूछने की अनुमति मिली। –

+0

उन वर्गों को गतिशील रूप से उत्पन्न करने का अच्छा विचार। मैं इसे शामिल करने के लिए अपने उत्तर को संपादित करने का प्रयास करूंगा। – mr100

संबंधित मुद्दे