2011-02-07 10 views
38

मैं निम्नलिखित हस्ताक्षरसी #: गतिशील क्रम डाली

dynamic Cast(object obj, Type castTo); 

किसी को भी ऐसा करने के लिए कैसे पता के साथ एक विधि को लागू चाहते हैं? obj निश्चित रूप से कास्ट लागू करता है लेकिन मेरे कुछ ऐप के रनटाइम बाध्यकारी सामानों को काम करने के लिए ठीक से डालने की आवश्यकता है।

संपादित करें: अगर कुछ उत्तर मतलब नहीं है क्योंकि मैं शुरू में गलती से dynamic Cast(dynamic obj, Type castTo); टाइप किया है - मेरा मतलब है इनपुट object या कुछ अन्य गारंटी आधार वर्ग होना चाहिए

+0

क्या आप कह रहे हैं कि आपको गतिशील रूप से एक निहित या स्पष्ट रूपांतरण ऑपरेटर को कॉल करने की आवश्यकता है? – Gabe

+0

या तो एक, लेकिन फिलहाल, –

उत्तर

58

मुझे लगता है कि आप यहां कास्टिंग और कनवर्ट करने के मुद्दों को भ्रमित कर रहे हैं।

  • कास्टिंग: किसी ऑब्जेक्ट को इंगित करने वाले संदर्भ के प्रकार को बदलने का कार्य। या तो ऑब्जेक्ट पदानुक्रम या एक कार्यान्वित इंटरफेस को ऊपर या नीचे ले जाना
  • कनवर्ट करना: किसी भिन्न प्रकार के मूल स्रोत ऑब्जेक्ट से एक नई वस्तु बनाना और उस प्रकार के संदर्भ के माध्यम से इसे एक्सेस करना।

सी # में 2 के बीच अंतर जानने में अक्सर मुश्किल होती है क्योंकि उनमें से दोनों एक ही सी # ऑपरेटर: कास्ट का उपयोग करते हैं।

इस स्थिति में आप लगभग निश्चित रूप से कास्ट ऑपरेशन की तलाश नहीं कर रहे हैं।dynamic को dynamic पर कास्टिंग करना अनिवार्य रूप से एक पहचान रूपांतरण है। यह कोई मूल्य प्रदान नहीं करता है क्योंकि आप एक ही अंतर्निहित वस्तु पर dynamic संदर्भ प्राप्त कर रहे हैं। परिणामी लुकअप कोई अलग नहीं होगा।

इसके बजाय आप जो परिदृश्य में दिखना चाहते हैं वह एक रूपांतरण है। यह अंतर्निहित वस्तु को एक अलग प्रकार के रूप में बदल रहा है और परिणामस्वरूप ऑब्जेक्ट को dynamic फैशन में एक्सेस कर रहा है। इसके लिए सबसे अच्छा एपीआई Convert.ChangeType है।

public static dynamic Convert(dynamic source, Type dest) { 
    return Convert.ChangeType(source, dest); 
} 

संपादित

अद्यतन सवाल निम्न पंक्ति है:

निश्चित रूप से castTo

लागू करता obj इस मामले तो Cast विधि करता है नहीं तो अस्तित्व की जरूरत है। स्रोत object को केवल dynamic संदर्भ के लिए असाइन किया जा सकता है।

dynamic d = source; 

ऐसा लगता है कि तुम क्या हासिल करने की कोशिश कर रहे हैं एक dynamic संदर्भ के माध्यम से source के पदानुक्रम में एक विशेष इंटरफ़ेस या प्रकार देख रहा है की तरह। यह बस संभव नहीं है। परिणामस्वरूप dynamic संदर्भ कार्यान्वयन ऑब्जेक्ट को सीधे देखेगा। यह स्रोत के पदानुक्रम में किसी विशेष प्रकार को नहीं देखता है। तो पदानुक्रम में एक अलग प्रकार के लिए कास्टिंग करने का विचार और फिर dynamic पर वापस पहली बार dynamic को असाइन करने के समान है। यह अभी भी एक ही अंतर्निहित वस्तु को इंगित करेगा।

+0

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

+1

@ जॉर्ज उस मामले में क्यों न सिर्फ 'गतिशील' पर डाला गया? अंतर्निहित ऑपरेशन वास्तव में एक कास्ट की आवश्यकता नहीं होनी चाहिए यदि अंतर्निहित ऑपरेशन – JaredPar

+0

उपयोग केस बेसटाइप का एक ऑब्जेक्ट पास किया गया है, और मेरे पास एक IList हैंडलर हैं जहां प्रत्येक हैंडलर IHandle लागू करता है जहां टी: बेस टाइप। मुझे उन सभी हैंडलर को चलाने की ज़रूरत है जो इस विशेष प्रकार पर लागू होते हैं क्योंकि गतिशील सही ढंग से अनुमान नहीं लगा सकता है (हो सकता है क्योंकि IHandle covariant है)। मैं इसे प्रतिबिंब का उपयोग कर काम कर रहा था लेकिन ओई vey। सी # में –

0

एक सामान्य का प्रयास करें:

public static T CastTo<T>(this dynamic obj, bool safeCast) where T:class 
{ 
    try 
    { 
     return (T)obj; 
    } 
    catch 
    { 
     if(safeCast) return null; 
     else throw; 
    } 
} 

यह विस्तार विधि प्रारूप में है तो इसके उपयोग के रूप में अगर यह गतिशील वस्तुओं के एक सदस्य थे होगा:

dynamic myDynamic = new Something(); 
var typedObject = myDynamic.CastTo<Something>(false); 

संपादित करें: Grr, वह नहीं देखा था। हाँ, आप संजीदगी से सामान्य बंद कर सकता है, और यह एक गैर सामान्य विस्तार विधि में छिपाने के लिए मुश्किल नहीं होगा:

public static dynamic DynamicCastTo(this dynamic obj, Type castTo, bool safeCast) 
{ 
    MethodInfo castMethod = this.GetType().GetMethod("CastTo").MakeGenericMethod(castTo); 
    return castMethod.Invoke(null, new object[] { obj, safeCast }); 
} 

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

+1

यह काम नहीं करता है (प्रतिबिंब के बिना) यदि 'टी' संकलन प्रकार पर ज्ञात नहीं है। – jason

+0

@ किथ्स, रनटाइम के दौरान प्रकार प्रदान किया जाता है। मुझे पता है, मत पूछो। मुझे लगता है कि मैं इसे लिख सकता हूं और जेनेरिक को बंद करने के लिए प्रतिबिंब का उपयोग कर सकता हूं लेकिन एक बेहतर तरीका होना चाहिए। –

+1

@ जॉर्ज: मुझे विश्वास नहीं है कि आप यहां प्रतिबिंब का उपयोग करके घूमने में सक्षम होंगे। –

-2
वैकल्पिक रूप से

:

public static T Cast<T>(this dynamic obj) where T:class 
{ 
    return obj as T; 
} 
+2

आवश्यकता यह प्रतीत होती है कि प्रकार रनटाइम पर निर्दिष्ट है। – Jimmy

20

यह काम करना चाहिए:

public static dynamic Cast(dynamic obj, Type castTo) 
{ 
    return Convert.ChangeType(obj, castTo); 
} 

संपादित

मैं निम्नलिखित परीक्षण कोड लिखा है:

var x = "123"; 
var y = Cast(x, typeof(int)); 
var z = y + 7; 
var w = Cast(z, typeof(string)); // w == "130" 

यह PHP, जावास्क्रिप्ट या पायथन जैसे भाषाओं में "टाइपकास्टिंग" जैसा दिखता है (क्योंकि यह वांछित प्रकार के मान परिवर्तित करता है)। मुझे नहीं पता कि यह एक अच्छी बात है, लेकिन यह निश्चित रूप से काम करता है ... :-)

+0

CastTo को काम करने के लिए एक वैल्यू टाइप का वर्णन करना होगा। – KeithS

+0

हम्म, इसे आजमाने के बारे में, लेकिन क्या यह हमेशा ऑब्जेक्ट पर इस डाउनकास्ट को वापस नहीं करेगा? –

+0

@ किथ: बस इसका परीक्षण किया गया, और यह 'स्ट्रिंग' के साथ काम करता है (जो एक वर्ग है, मूल्य प्रकार नहीं है)। – rsenna

7

बेस्ट मैं अब तक मिल गया:

dynamic DynamicCast(object entity, Type to) 
{ 
    var openCast = this.GetType().GetMethod("Cast", BindingFlags.Static | BindingFlags.NonPublic); 
    var closeCast = openCast.MakeGenericMethod(to); 
    return closeCast.Invoke(entity, new[] { entity }); 
} 
static T Cast<T>(object entity) where T : class 
{ 
    return entity as T; 
} 
+0

आपकी प्रारंभिक टिप्पणी के बाद मैंने जो कुछ भी समाप्त किया था, उससे काफी कुछ। – KeithS

+2

यह मुझे समझ में नहीं आता है। कॉल 'डायनामिककास्ट (ओबीजे, टाइपोफ (फू))' '(गतिशील) ओबीजे 'से अलग है, सिवाय इसके कि आपको उस मामले में शून्य संदर्भ मिलता है जहां' obj' (जिसमें *** संकलन-समय ** है) * टाइप 'ऑब्जेक्ट')' फू 'नहीं होता है? इसके अलावा, बाधा 'जहां टी: ऑब्जेक्ट' व्यर्थ और अस्वीकृत है। –

+1

@JeppeStigNielsen यह मुक्केबाजी का मामला है। मान लीजिए कि आपके पास 'गेटफुलनाम' विधि और 'प्रोफेसर: व्यक्ति' के साथ 'व्यक्ति' है जो 'पीएचडी "के साथ प्रत्यय करने के लिए' गेटफुलनाम 'को ओवरराइड करता है। अब मान लीजिए कि इकाई प्रकार 'प्रोफेसर' है लेकिन हमारी विधि के बाहर 'व्यक्ति' के रूप में डाली गई है, हो सकता है कि यह ओआरएम या मॉडल बाइंडर या कुछ द्वारा लोड किया गया हो। यदि आप '(गतिशील) योग्यता को कॉल करते हैं) .GetFullName()' यह 'Person.GetFullName()' चलाएगा। यह एक लंबा समय रहा है क्योंकि यह मुद्दा मेरे लिए आया है, इसलिए विनिर्देश थोड़ा गलत हो सकते हैं लेकिन इसे इसके साथ करना पड़ा। –

6

ओपनसोर्स ढांचे Dynamitey एक स्थिर विधि है कि others के बीच डाली रूपांतरण सहित डीएलआर का उपयोग कर लेट बाइंडिंग करता है।

dynamic Cast(object obj, Type castTo){ 
    return Dynamic.InvokeConvert(obj, castTo, explict:true); 
} 

एक Cast<T> प्रतिबिंब का उपयोग कर कहा जाता है पर इस का लाभ यह है कि यह भी किसी भी IDynamicMetaObjectProvider गतिशील रूपांतरण ऑपरेटरों है, यानी के लिए काम करेगा। DynamicObject पर कोशिश करें।

3

मुझे एहसास हुआ कि इसका उत्तर दिया गया है, लेकिन मैंने एक अलग दृष्टिकोण का उपयोग किया और सोचा कि यह साझा करने लायक हो सकता है। इसके अलावा, मुझे लगता है कि मेरा दृष्टिकोण अवांछित उपरि का उत्पादन कर सकता है। हालांकि, मैं पर्यवेक्षक या कुछ भी गणना करने में सक्षम नहीं हूं जो कि हम जो भार देखते हैं उसके तहत बुरा है। मैं इस दृष्टिकोण पर किसी भी उपयोगी प्रतिक्रिया की तलाश में था।

गतिशीलता के साथ काम करने में समस्या यह है कि आप गतिशील वस्तु पर सीधे किसी भी कार्य को संलग्न नहीं कर सकते हैं। आपको ऐसा कुछ उपयोग करना है जो असाइनमेंट को समझ सके जो आप हर बार समझना नहीं चाहते हैं।

इस सरल समाधान की योजना बनाते समय, मैंने देखा कि वैध मध्यस्थों को समान वस्तुओं को फिर से टाइप करने का प्रयास करते समय क्या होता है। मैंने पाया कि एक बाइनरी सरणी, स्ट्रिंग (एक्सएमएल, जेसन) या हार्ड कोडिंग रूपांतरण (IConvertable) सामान्य दृष्टिकोण थे। मैं कोड रखरखाव कारक और आलस्य के कारण द्विआधारी रूपांतरण में नहीं आना चाहता हूं।

मेरा सिद्धांत यह था कि Newtonsoft स्ट्रिंग मध्यस्थ का उपयोग करके ऐसा कर सकता है।

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

सी #:

//This lives in a helper class 
public static ConvertDynamic<T>(dynamic data) 
{ 
    return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(Newtonsoft.Json.JsonConvert.SerializeObject(data)); 
} 

//Same helper, but in an extension class (public static class), 
//but could be in a base class also. 
public static ToModelList<T>(this List<dynamic> list) 
{ 
    List<T> retList = new List<T>(); 
    foreach(dynamic d in list) 
    { 
     retList.Add(ConvertDynamic<T>(d)); 
    } 
} 
इसी के साथ

ने कहा, यह एक और उपयोगिता मैं एक साथ रख दिया मुझे एक गतिशील में किसी भी वस्तु की सुविधा देता है फिट बैठता है। मुझे पता है कि मुझे सही ढंग से ऐसा करने के लिए प्रतिबिंब का उपयोग करना था:

public static dynamic ToDynamic(this object value) 
{ 
    IDictionary<string, object> expando = new ExpandoObject(); 

    foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType())) 
     expando.Add(property.Name, property.GetValue(value)); 

    return expando as ExpandoObject; 
} 

मुझे उस समारोह को पेश करना पड़ा। एक गतिशील टाइप किए गए चर को सौंपा गया एक मनमाना ऑब्जेक्ट को IDictionary में परिवर्तित नहीं किया जा सकता है, और कनवर्ट डायनामिक फ़ंक्शन को तोड़ देगा। इस फ़ंक्शन चेन का उपयोग करने के लिए इसे सिस्टम की गतिशीलता प्रदान की जानी चाहिए। डायनामिक.एक्सपांडाऑब्जेक्ट, या आईडीकी < स्ट्रिंग, ऑब्जेक्ट >।

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