2013-08-29 7 views
13

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

उदाहरण के लिए लें, अगर इस वर्ग है:

public class Row<T> 
{ 
    public static explicit operator Row<object>(Row<T> o) 
    { 
     return new Row<object> 
     { 
      Name = o.Name, 
      Value = o.Value 
     }; 
    } 

    public string Name { get; set; } 

    public T Value { get; set; } 
} 

एक से कास्टिंग कहना Row<bool>Row<object> कार्यों के लिए:

var a = new Row<bool> 
    { 
     Name = "Foo", 
     Value = true 
    }; 

    var b = (Row<object>)a; // Works 

लेकिन यह लगता है जब मैं object से Row<object> पर जाने की कोशिश मेरे स्पष्ट ऑपरेटर को अनदेखा करें और एक सिस्टम फेंक दें। इन्वालिड कैस्ट अपवाद:

var c = (object) a; // Simulate getting from reflection 

var d = (Row<object>) c; // System.InvalidCastException 

मुझे क्या याद आ रही है?

+0

ऐसा करें यह var c = (पंक्ति ) ए की तरह करें; – Ehsan

+1

सुनिश्चित नहीं है कि आप क्या उम्मीद करते हैं - आपके नमूने में कोई 'स्पष्ट ऑपरेटर पंक्ति (ऑब्जेक्ट ओ)' नहीं है ... –

+0

ऐसा इसलिए हो सकता है क्योंकि स्पष्ट ऑपरेटर को 'पंक्ति ' की उम्मीद है जबकि आप इसे 'ऑब्जेक्ट' दे रहे हैं। –

उत्तर

4

समस्या है कि यहाँ कास्टिंग एक रूपांतरण ऑपरेटर के लिए नहीं लगता है जब तक कि एक पर परिभाषित किया गया है है उस मूल्य का स्थिर प्रकार जिसे आप कास्ट करने का प्रयास कर रहे हैं। आपके उदाहरण में c का स्थिर प्रकार object और object न तो से प्राप्त होता है और न ही रूपांतरण ऑपरेटर Row<object> होता है, जिसके परिणामस्वरूप रनटाइम अपवाद होता है।

ऐसा लगता है कि इस समस्या को आसानी से बेहतर डिजाइन के साथ हटाया जा सकता है।

आप किसी भी प्रकार के Row<T> को Row<object> के रूप में देखना चाहते हैं और रूपांतरण ऑपरेटर इस तथ्य के आसपास काम से अधिक कुछ नहीं करता है कि ये प्रकार श्रेणीबद्ध रूप से संबंधित नहीं हैं। तो क्यों उन्हें पहले से समस्या से संबंधित नहीं है और समस्या से बचें?

उदाहरण के लिए:

  • कास्टिंग समस्या हल हो रहा है क्योंकि आप अब आधार वर्ग को Row<T> किसी भी प्रकार की डाल सकता है (जो लेता है:

    public abstract class Row 
    { 
        public string Name { get; set; } 
    
        public object Value { get; protected set; } 
    } 
    
    public class Row<T> : Row 
    { 
        public new T Value 
        { 
         get { return (T)base.Value; } 
         set { base.Value = value; } 
        } 
    } 
    

    यह है कि तुम क्या चाहते हो रहा है अपने प्रारंभिक डिज़ाइन में Row<object> की ज़िम्मेदारियों पर) और आसानी से Name और Value तक पहुंचें, इससे कोई फर्क नहीं पड़ता कि Value किस प्रकार है।

  • Row.Value सेटर संरक्षित है ताकि आप Row<int> से पर डालें और Value उदा। टाइप सुरक्षा से बनाए रखने के बाहर से string
+0

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

6

उपयोग object के बजाय dynamic क्रम वास्तविक प्रकार की जांच के लिए मजबूर करने:

var c = (dynamic)a; 
var d = (Row<object>)c; // Works fine 

यह अपने Row<T> -> Row<object> डाली ऑपरेटर कॉल करेंगे।

+1

आप 'स्पष्ट ऑपरेटर पंक्ति (ऑब्जेक्ट ओ) घोषित नहीं कर सकते हैं। –

+0

@AdamHouldsworth यह सही है। – MarcinJuraszek

+0

विजुअल स्टूडियो शिकायत करता है ... तो मुझे पहले ऑब्जेक्ट प्रतिबिंब रिटर्न को मेरे प्रकार के गतिशील पर डालना चाहिए? – Phil

2

आप प्रतिबिंब के साथ ऐसा कर सकते हैं:

public class RowHelper 
{ 
    public static Row<object> LoadRow(object o) 
    { 
     var type = o.GetType(); 
     return new Row<object> 
     { 
      Name = (string)type.InvokeMember("Name", BindingFlags.GetProperty, null, o, null), 
      Value = type.InvokeMember("Value", BindingFlags.GetProperty, null, o, null) 
     }; 
    } 
} 

आप के साथ इस कहेंगे:

var d = RowHelper.LoadRow(c); 
संबंधित मुद्दे