2015-12-23 11 views
7

मैं कुछ कोड है कि एक गुण सेट करने की कोशिश करता विरासत में मिली फेंक देगा:चेक कि क्या PropertyInfo.SetValue एक ArgumentException

object target = ... // some instance on which we want to set a property 
object value = ...  // some value - in this case, a string 
var propertyInfo = ... // some property of target - in this case, not a string 

try 
{ 
    propertyInfo.SetValue(obj, value, null); 
} 
catch (ArgumentException) 
{ 
    // We go off and look for our own way of converting between 
    // the type of value and the type of the property. 
} 

वर्तमान उपयोग अपवाद पकड़ लिया और एक बहुत फेंक दिया जाता है में, तो मैं एक बनाने के लिए चाहते हैं पहले जांचें:

if (propertyInfo.PropertyType.IsAssignableFrom(value.GetType()) 
{ 
    // Try/catch as above 
} 
else 
{ 
    // Do the manual conversion as if the exception had been thrown. 
} 

यह बहुत तेज़ चलता है। हालांकि, मेरी एक चिंता यह है कि IsAssignableFromfalse कुछ प्रकार के लिए SetValue वास्तव में सफल होगा। (यह हमारे कारण मैनुअल रूपांतरण के लिए देखने के लिए जब हम करने के लिए एक मूल्य के पूरी तरह स्थापित करने के लिए असफल हो की जरूरत नहीं है, और संभवतः होगा।)

SetValue के लिए कल्पना का कहना है

मूल्य नहीं बदला जा सकता PropertyType

जो कि असाइनमेंट के समान बिल्कुल नहीं है।

(यदि IsAssignableFrom रिटर्न मामलों में जहां SetValue विफल रहता है, यह ठीक है में true -। मैनुअल रूपांतरण अभी भी नहीं होगा)

किसी ने मुझे के लिए पुष्टि कर सकते हैं कि क्या यह संभव है या नहीं?

+1

कृपया ऐसा वास्तविक उदाहरण दें जहां यह होता है। संभवतः आपके पास एक है, इसलिए यह एक छोटा लेकिन पूरा उदाहरण देना वास्तव में आसान होना चाहिए जो 'IsAssignableFrom' लॉग करता है और सफलतापूर्वक' SetValue 'को कॉल करता है। (यह * केवल primitives के साथ एक मुद्दा हो सकता है, जो उचित रूप से आसानी से पता लगाया जा सकता है ...) –

+0

@ जोन मैं जो असफलता देख रहा हूं वह एक कस्टम प्रकार की संपत्ति के लिए 'स्ट्रिंग' असाइन करने का प्रयास कर रहा है जो 'स्ट्रिंग' से असाइन नहीं किया जा सकता है (लेकिन जिसके लिए हमारे पास कस्टम कनवर्टर है)। हालांकि, यह कोड किसी अन्य प्रकार को किसी भी प्रकार से सेट कर सकता है और मैं इसे तोड़ना नहीं चाहता, इसलिए मुझे सामान्य मामले में रूचि है। – Rawling

+0

खैर मुझे आश्चर्य है कि 'SetValue' एक कस्टम कनवर्टर कॉल करेगा - लेकिन फिर, एक पूर्ण उदाहरण यह स्पष्ट करेगा। –

उत्तर

1

आप संदिग्ध के रूप में, प्रकार short के एक मूल्य प्रतिबिंब के माध्यम से प्रकार int की एक संपत्ति के लिए आबंटित है, typeof(int).IsAssignableFrom(typeof(short)) हालांकि रिटर्न false

ArgumentException की स्टैकट्रेस को देखते हुए:

at System.RuntimeType.TryChangeType(Object value, Binder binder, CultureInfo culture, Boolean needsSpecialCast) 
    at System.RuntimeType.CheckValue(Object value, Binder binder, CultureInfo culture, BindingFlags invokeAttr) 
    at System.Reflection.MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig) 
    at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) 
    at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) 
    at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture) 
    at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, Object[] index) 
    at System.Reflection.PropertyInfo.SetValue(Object obj, Object value) 
    at ConsoleApplication3.Program.Main(String[] args) in ... 

अपवाद RuntimeType.TryChangeType में फेंक दिया है। mscorlib में स्रोत को देखते हुए:

// System.RuntimeType 
[SecurityCritical] 
private object TryChangeType(object value, Binder binder, CultureInfo culture, bool needsSpecialCast) 
{ 
    ... 
    if (this.IsInstanceOfType(value)) 
    { 
     return value; 
    } 
    ... 
     if (RuntimeType.CanValueSpecialCast(valueType, this)) 
     { 
    ... 
    } 
    throw new ArgumentException(string.Format(CultureInfo.CurrentUICulture, Environment.GetResourceString("Arg_ObjObjEx"), value.GetType(), this)); 
} 

दुर्भाग्य से कई आंतरिक कार्यों को निर्धारित करने के लिए एक ArgumentException फेंक दिया जाना चाहिए कहा जाता है। मुझे लगता है कि पुरातन के रूपांतरण इस समारोह के आसपास कहीं नियंत्रित किया जाता है:

bool flag = base.IsPointer || this.IsEnum || base.IsPrimitive; 
if (flag) 
{ 
    ... 
    if (RuntimeType.CanValueSpecialCast(valueType, this)) 
    { 
    ... 
    } 
} 

तो यह सूचक, enum और आदिम प्रकार की तरह लग रहा नियंत्रित किया जाता है:

// System.RuntimeType 
[SecurityCritical] 
[MethodImpl(MethodImplOptions.InternalCall)] 
private static extern bool CanValueSpecialCast(RuntimeType valueType, RuntimeType targetType); 

वहाँ System.RuntimeType.CheckValue(object, Binder, CultureInfo, BindingFlags) में कुछ रोचक कोड के रूप में अच्छी तरह से है एक अलग तरीके से। मैं आपको उस तर्क की प्रतिलिपि बनाने का प्रयास करने के लिए हतोत्साहित करता हूं। IsAssignableFrom का उपयोग करना आसान हो सकता है, और अभिन्न प्रकारों को अलग से संभाल सकता है। पॉइंटर, एनम और आदिम प्रकार के तर्कों को संभालना बहुत जटिल लग रहा है, मैं बस try-catch पर गिर जाऊंगा। हालांकि, यदि कोई तर्क त्रुटि हुई तो आप कैश कर सकते हैं ताकि उसी पैरामीटर प्रकार के साथ उसी विधि पर बाद की कॉल कुछ हद तक तेज हो।

+0

धन्यवाद, हेज। मुझे बस 'लम्बा'/'int' उदाहरण खुद मिल गया होगा, लेकिन आपने यह पता लगाने में काफी बेहतर किया है कि मेरे पास तर्क कहां और क्या है, और कैशिंग विचार बहुत अच्छा है - मैं शायद नीचे जा रहा हूं मार्ग। – Rawling

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