2011-11-18 8 views
5

में इस प्रकार का कास्टिंग करने का कोई तरीका है, मैं एक सामान्य विधि बनाने की कोशिश कर रहा हूं जो किसी XML दस्तावेज़ में तत्व ढूंढने के लिए एक अनुमान वापस कर देगा।क्या सी # भविष्यवाणी

मूल रूप से कुछ इस तरह:

private static Func<XElement, bool> GetPredicate<T>(Criterion criterion) 
{ 
    switch (criterion.CriteriaOperator) 
    { 
     case CriteriaOperator.Equal: 
      return x => (T)x.Attribute(criterion.PropertyName) == 
       (T)(criterion.PropertyValue); 
     case CriteriaOperator.GreaterThan: 
      return x => (T)x.Attribute(criterion.PropertyName) > 
       (T)(criterion.PropertyValue); 
     case CriteriaOperator.GreaterThanOrEqual: 
      return x => (T)x.Attribute(criterion.PropertyName) >= 
       (T)(criterion.PropertyValue); 
     case CriteriaOperator.LessThan: 
      return x => (T)x.Attribute(criterion.PropertyName) < 
       (T)(criterion.PropertyValue); 
     case CriteriaOperator.LessThanOrEqual: 
      return x => (T)x.Attribute(criterion.PropertyName) <= 
       (T)(criterion.PropertyValue); 
     case CriteriaOperator.NotEqual: 
      return x => (T)x.Attribute(criterion.PropertyName) != 
       (T)(criterion.PropertyValue); 
     default: 
      throw new ArgumentException("Criteria Operator not supported."); 
    } 
} 

केवल बात यह है कि इस संकलन नहीं करता है। समस्या (T)x.Attribute(criterion.PropertyName) हिस्सा है जहां संकलक इंगित करता है पर है:

प्रकार 'System.Xml.Linq.XAttribute' 'टी'

वर्तमान में मेरे पास दो तरीकों टाइप करने के लिए की अभिव्यक्ति नहीं दिया जा सकता है कि एक जैसे हैं जो कि एक को डबल करने के लिए और दूसरे को दशमलव के लिए छोड़ देता है। मैं वास्तव में उस तरह की नकल नहीं करना चाहूंगा।

+0

क्या 'Criterion' है? –

+0

@ डैनियलए। व्हाइट: एक कस्टम क्लास जिसमें बूलियन अभिव्यक्ति के लिए डेटा शामिल है। PropertyName एक स्ट्रिंग है जो एक्सएमएल नोड में विशेषता नाम का प्रतिनिधित्व करती है, जिसके खिलाफ मैं मेल खाता हूं और PropertyValue उस ऑब्जेक्ट के साथ एक ऑब्जेक्ट है जिसे मैं ढूंढ रहा हूं। –

उत्तर

1

XAttribute Class को परिभाषित करता है कई conversion operators। हालांकि, जब एक सामान्य प्रकार पैरामीटर T पर कास्टिंग करते हैं, तो इन ऑपरेटरों को ध्यान में नहीं रखा जाता है।

आप क्या कर सकते हैं क्रम में लैम्ब्डा अभिव्यक्ति का निर्माण इस प्रकार है:

private static Func<XElement, bool> GetPredicate<T>(Criterion criterion) 
{ 
    var arg = Expression.Parameter(typeof(XElement), "arg"); 
    var name = Expression.Constant((XName)criterion.PropertyName); 
    var attr = Expression.Call(arg, "Attribute", null, name); 
    var left = Expression.Convert(attr, typeof(T)); 
    var right = Expression.Constant(criterion.PropertyValue, typeof(T)); 

    Expression body; 

    switch (criterion.CriteriaOperator) 
    { 
    case CriteriaOperator.Equal: 
     body = Expression.Equal(left, right); 
     break; 
    case CriteriaOperator.GreaterThan: 
     body = Expression.GreaterThan(left, right); 
     break; 
    default: 
     throw new ArgumentException("Criteria Operator not supported."); 
    } 

    return Expression.Lambda<Func<XElement, bool>>(body, arg).Compile(); 
} 

उपयोग:

var f = GetPredicate<int>(new Criterion("documentversion", CO.GreaterThan, 8)); 
var g = GetPredicate<string>(new Criterion("documentid", CO.Equal, "DOC-5X")); 
var h = GetPredicate<double>(new Criterion("documentprice", CO.Equal, 85.99d)); 
+0

यह लगभग काम किया। एक स्ट्रिंग प्रकार के लिए यह ठीक काम करता था, लेकिन डबल के लिए यह var right = Expression.Constant (मानदंड। प्रॉपर्टी वैल्यू, टाइपोफ (टी)) पर एक ArgumentException के साथ विफल रहा "तर्क प्रकार मेल नहीं खाते"। –

+0

इस मामले में 'टी'' मानदंड में मूल्य के प्रकार से मेल नहीं खाता है। प्रॉपर्टीवैल्यू'। मैंने कुछ कामकाजी उदाहरण जोड़े हैं। – dtb

1

कोई implicit or explicit conversions कोई मनमाना प्रकार T पर कोई implicit or explicit conversions नहीं है। केवल रूपांतरण XAttribute से एक और प्रकार की अनुमति दी स्पष्ट कर रहे हैं और इन प्रकार के लिए:

आपको उपरोक्त प्रकारों में से एक को अधिभारित करना होगा, और कॉल को उन में से किसी एक को सीमित करना होगा।

0

T क्या होना चाहिए? एक XAttribute तब तक परिवर्तित नहीं किया जा सकता जब तक कि सामान्य पर किसी प्रकार की बाधा न हो। किसी भी मामले में, आप शायद Attribute().Value प्राप्त करना चाहते हैं, जो एक स्ट्रिंग है। फिर आप एक तुलना कर सकते हैं। criterion.PropertyValue का प्रकार क्या है?

यदि आपके एक्सएमएल में संख्याओं जैसे प्राइमेटिव हैं, तो आप स्ट्रिंग को सीधे किसी नंबर पर नहीं डाल सकते हैं। आपको double.TryParse() जैसी विधियों का उपयोग करने की आवश्यकता है। दुर्भाग्य से TryParse विधि रखने के लिए जेनेरिक को बाधित करने का कोई तरीका नहीं है। यदि वहां थे, तो आप T.TryParse कह सकेंगे। लेकिन कोई रास्ता नहीं है, इसलिए आप नहीं कर सकते। जेनेरिक शायद इस के साथ आपकी मदद नहीं करेंगे।

+0

एक्सएट्रिब्यूट क्लास कई [रूपांतरण ऑपरेटरों] को परिभाषित करता है (http://msdn.microsoft.com/en-us/library/ff986944.aspx)। – dtb

+0

@ डीटीबी वाह यह बेहद उपयोगी है। धन्यवाद। दुर्भाग्य से यह ओपी में मदद करने के लिए प्रतीत नहीं होता है। – Tesserex

+0

@ टेसेरेक्स: वास्तव में, यह करता है। अन्य प्रकारों के लिए परिभाषित स्पष्ट जानवर हैं, आप मनमाने ढंग से टाइप नहीं कर सकते हैं। आपका सुझाव केवल उस कोड को बाधित करेगा जो 'XAttribute' में है जो पहले से ही कुछ प्रकार के लिए एक्सएमएल-विशिष्ट स्वरूपण को संभालता है और संभवतः तोड़ देगा। – casperOne

-1

सामान्य पद्धति पर XAttribute constrait जोड़ें:

GetPredicate<T>(Criterion criterion) where T : XAttribute 
+0

-1 समस्या यह है कि 'XAttribute' में मनमानी प्रकार' टी' के स्पष्ट रूपांतरण नहीं हैं।उपरोक्त समस्या को हल नहीं करेगा – casperOne

+0

@RedHat: यह बिल्कुल इरादा नहीं है। विचार यह है कि भविष्यवाणी x => x.Attribute ("documentversion")> 8 या किसी भिन्न मामले में x => x.Attribute ("documentid") == "DOC-5X" या event x => x.Attribute ("documentprice") <= "85.99"। –

1

तुम सिर्फ dynamic को डाले साथ T करने के लिए अपने डाले की जगह है, यह तब काम करेंगे। मुझे यहां प्रकार की सुरक्षा को फेंकने के बारे में बुरा नहीं लगेगा क्योंकि आप शायद यह सुनिश्चित नहीं कर सकते कि एक्सएमएल विशेषताओं में सामान वैसे भी सही प्रकार है - इसलिए टाइप सुरक्षा एक भ्रम था।

+0

हालांकि यह एक बहुत ही आशाजनक और सरल विकल्प था, लेकिन यह काम नहीं करता था। समान और समान विकल्प के लिए काम करता है, लेकिन दूसरों के लिए हमेशा एक अपवाद होता है कि स्ट्रिंग (विशेषता मान) की तुलना डबल (PropertyValue मान) से नहीं की जा सकती है। –

0

आप का उपयोग कर एस की तुलना नहीं कर सकते हैं, लेकिन object.Equals() काम करना चाहिए।

रूपांतरण करने के लिए, आप Convert.ChangeType() इस्तेमाल कर सकते हैं:

case CriteriaOperator.Equal: 
    return x => object.Equals(
     Convert.ChangeType(x.Attribute(criterion.PropertyName).Value, typeof(T)), 
     criterion.PropertyValue); 

इस के साथ समस्या यह है (जैसे Double.PositiveInfinityINF के रूप में प्रस्तुत किया जाता है) है कि XML कुछ मामलों में रूपांतरण के लिए अलग नियम का उपयोग करता है।

इसे हल करने के लिए, आप the XmlConvert class का उपयोग कर सकते हैं, जिसका उपयोग रूपांतरण ऑपरेटरों द्वारा आंतरिक रूप से किया जाता है। सिवाय यह Convert.ChangeType() की तरह एक "सामान्य" विधि नहीं है, तो आप बनाना होगा अपनी खुद की:

private static object Convert(string value, Type targetType) 
{ 
    if (targetType == typeof(double)) 
     return XmlConvert.ToDouble(value); 

    … 

    throw new ArgumentException(); 
} 

… 

case CriteriaOperator.Equal: 
    return x => object.Equals(
     Convert(x.Attribute(criterion.PropertyName).Value, typeof(T)), 
     criterion.PropertyValue); 
+0

यह उन चीजों के लिए वास्तव में समस्या पर हमला नहीं करता है जो तुलना ऑपरेटर की तरह समानता जांच नहीं हैं। – mquander

+0

आप सही हैं। मैंने इसके बारे में नहीं सोचा था। हालांकि मुझे लगता है कि कई प्रकार के प्रश्न गैर-जेनेरिक 'आईसीओम्पेर्बल' को लागू करते हैं, ताकि इसका ख्याल रखा जा सके। – svick