मैं पैरेंट क्लास से चाइल्ड क्लास में कास्ट करने की कोशिश कर रहा हूँ, लेकिन मुझे एक InvalidCastException मिलती है। बालक वर्ग के पास केवल एक प्रकार की संपत्ति होती है। क्या किसी को पता है कि मुझे क्या करने की आवश्यकता है?
मैं पैरेंट क्लास से चाइल्ड क्लास में कास्ट करने की कोशिश कर रहा हूँ, लेकिन मुझे एक InvalidCastException मिलती है। बालक वर्ग के पास केवल एक प्रकार की संपत्ति होती है। क्या किसी को पता है कि मुझे क्या करने की आवश्यकता है?
जवाबों:
सी # में डाउनकास्ट करने का एक सरल तरीका माता-पिता को क्रमबद्ध करना है और फिर इसे बच्चे में शामिल करना है।
var serializedParent = JsonConvert.SerializeObject(parentInstance);
Child c = JsonConvert.DeserializeObject<Child>(serializedParent);
मेरे पास एक सरल कंसोल ऐप है जो पशु को कुत्ते में डालती है, ऊपर की दो पंक्तियों का उपयोग करके यहां पर
आप एक कुत्ते में एक स्तनपायी नहीं डाल सकते हैं - यह एक बिल्ली हो सकती है।
आप एक सैंडविच में भोजन नहीं डाल सकते हैं - यह एक चीज़बर्गर हो सकता है।
आप एक कार को फेरारी में नहीं डाल सकते हैं - यह एक होंडा, या अधिक विशेष रूप से हो सकता है, आप फेरारी 360 मोडेना को फेरारी 360 चैलेंज स्ट्रैडेल में नहीं डाल सकते हैं - अलग-अलग हिस्से हैं, भले ही वे दोनों फेरारी 360 हैं।
आपके बेस क्लास रेफरेंस का जो उदाहरण है, वह आपके चाइल्ड क्लास का उदाहरण नहीं है। कुछ गलत नहीं है।
अधिक विशेष रूप से:
Base derivedInstance = new Derived();
Base baseInstance = new Base();
Derived good = (Derived)derivedInstance; // OK
Derived fail = (Derived)baseInstance; // Throws InvalidCastException
कलाकारों के सफल होने के लिए, आप जो डाउनकास्टिंग कर रहे हैं, वह उस वर्ग का उदाहरण होना चाहिए जिसे आप डाउनकास्ट कर रहे हैं (या कम से कम, वह क्लास जिसे आप डाउनकास्टिंग कर रहे हैं, वह इंस्टेंस की श्रेणी पदानुक्रम के भीतर होना चाहिए), अन्यथा कास्ट विफल हो जाएगा।
कुछ मामले हैं जब इस तरह के कलाकारों को समझ में आता है।
मेरा मामला है, मुझे नेटवर्क पर एक आधार वर्ग प्राप्त हो रहा था, और मुझे इसके लिए और अधिक विशेषताओं की आवश्यकता थी। इसलिए इसे अपनी ओर से सभी घंटियाँ और सीटी जो मैं चाहता था, को संभालने के लिए प्राप्त किया गया था, और प्राप्त आधार वर्ग को DERIVED में डालना बस एक विकल्प नहीं था (कोर्स का अमान्य अमान्य विवरण)
एक व्यावहारिक थिंक-आउट-ऑफ-द-बॉक्स सॉल्यूशन एक एक्सेलेंस हेल्पर वर्ग की घोषणा करना था जो वास्तव में बेस क्लास को विरासत में नहीं मिला था, लेकिन इसे एक सदस्य के रूप में शामिल किया गया था।
public class BaseExtension
{
Base baseInstance;
public FakeDerived(Base b)
{
baseInstance = b;
}
//Helper methods and extensions to Base class added here
}
आप ढीला संयोजन है और बस के बिना आधार वर्ग के लिए अतिरिक्त सुविधाओं के एक जोड़े की जरूरत है वास्तव में व्युत्पत्ति की एक निरपेक्ष की जरूरत है, कि एक त्वरित और आसान समाधान का हो सकता है।
BaseExtensionयहां कम से कम ऐसा लागू हो IBaseकि आप इसे इसी तरह के संदर्भों में इस्तेमाल कर सकें? या अपनी आवश्यकताओं के लिए महत्वपूर्ण नहीं था?
मैंने ज्यादातर लोगों को यह कहते हुए देखा है कि बच्चे की कास्टिंग के लिए स्पष्ट माता-पिता संभव नहीं हैं, लेकिन वास्तव में यह सच नहीं है। आइए एक संशोधित शुरुआत करें और इसे उदाहरणों द्वारा साबित करने का प्रयास करें।
जैसा कि हम जानते हैं कि सभी नेटिंग में दो व्यापक श्रेणियां हैं।
संदर्भ प्रकार में तीन मुख्य स्थितिजन्य मामले हैं जिनमें कोई भी परिदृश्य झूठ बोल सकता है।
केस 1. किसी प्रत्यक्ष या अप्रत्यक्ष माता-पिता के लिए बच्चा
Employee e = new Employee();
Person p = (Person)e; //Allowed
केस 2. पैरेंट वैरिएबल पैरेंट ऑब्जेक्ट को रखना (अनुमति नहीं है)
Person p = new Person(); // p is true Person object
Employee e = (Employee)p; //Runtime err : InvalidCastException <-------- Yours issue
केस 3. पैरेंट वैरिएबल चाइल्ड ऑब्जेक्ट (हमेशा सफल)
नोट: क्योंकि वस्तुओं में बहुरूपी प्रकृति होती है, इसलिए माता-पिता वर्ग प्रकार के एक चर के लिए बच्चे के प्रकार को पकड़ना संभव है।
Person p = new Employee(); // p actually is Employee
Employee e = (Employee)p; // Casting allowed
निष्कर्ष: सभी से ऊपर पढ़ने के बाद, आशा है कि अब यह समझ में आएगा कि बाल रूपांतरण कैसे संभव है (केस 3)।
सवाल का जवाब है :
आपका उत्तर केस 2 में है। आप देख सकते हैं कि ऐसी कास्टिंग को ओओपी द्वारा अनुमति नहीं है और आप ओओपी के मूल नियम में से एक का उल्लंघन करने की कोशिश कर रहे हैं। हमेशा सुरक्षित रास्ता चुनें।
इसके अलावा, ऐसी असाधारण स्थितियों से बचने के लिए .net ने उपयोग करने की सिफारिश की है / ऑपरेटरों के रूप में वे आपको सूचित निर्णय लेने और सुरक्षित कास्टिंग प्रदान करने में मदद करेंगे।
यह वस्तु उन्मुख सिद्धांतों का उल्लंघन होगा। मैं कहूंगा कि एक सुरुचिपूर्ण समाधान यहाँ और परियोजना में कहीं और एक प्रक्षेपण को कॉन्फ़िगर करने के लिए AutoMapper जैसे ऑब्जेक्ट मैपिंग फ्रेमवर्क का उपयोग कर रहा है ।
यहाँ की तुलना में थोड़ा अधिक जटिल कॉन्फ़िगरेशन है, लेकिन ज्यादातर मामलों के लिए पर्याप्त लचीला है:
public class BaseToChildMappingProfile : Profile
{
public override string ProfileName
{
get { return "BaseToChildMappingProfile"; }
}
protected override void Configure()
{
Mapper.CreateMap<BaseClass, ChildClassOne>();
Mapper.CreateMap<BaseClass, ChildClassTwo>();
}
}
public class AutoMapperConfiguration
{
public static void Configure()
{
Mapper.Initialize(x =>
{
x.AddProfile<BaseToChildMappingProfile>();
});
}
}
जब एप्लिकेशन कॉल शुरू करता है AutoMapperConfiguration.Configure()और तब आप इस तरह से प्रोजेक्ट कर सकते हैं:
ChildClassOne child = Mapper.Map<BaseClass, ChildClassOne>(baseClass);
प्रॉपर्टी को कन्वेंशन द्वारा मैप किया जाता है, इसलिए यदि क्लास विरासत में मिली है तो प्रॉपर्टी के नाम बिल्कुल समान हैं और मैपिंग अपने आप कॉन्फ़िगर हो जाती है। कॉन्फ़िगरेशन को ट्विक करके आप अतिरिक्त गुण जोड़ सकते हैं। प्रलेखन देखें ।
पॉल, आपने यह नहीं पूछा 'क्या मैं यह कर सकता हूं' - मैं मान रहा हूं कि आप यह जानना चाहते हैं कि यह कैसे करना है!
हमें एक परियोजना पर ऐसा करना पड़ा - ऐसी कई कक्षाएं हैं जो हम एक बार में एक सामान्य शैली में स्थापित करते हैं, फिर व्युत्पन्न वर्गों के लिए विशिष्ट गुणों को शुरू करते हैं। मैं VB का उपयोग करता हूं, इसलिए मेरा नमूना VB (कठिन noogies) में है, लेकिन मैंने इस साइट से VB का नमूना चुरा लिया है जिसमें बेहतर C # संस्करण भी है:
नमूना कोड:
Imports System
Imports System.Collections.Generic
Imports System.Reflection
Imports System.Text
Imports System.Diagnostics
Module ClassUtils
Public Sub CopyProperties(ByVal dst As Object, ByVal src As Object)
Dim srcProperties() As PropertyInfo = src.GetType.GetProperties
Dim dstType = dst.GetType
If srcProperties Is Nothing Or dstType.GetProperties Is Nothing Then
Return
End If
For Each srcProperty As PropertyInfo In srcProperties
Dim dstProperty As PropertyInfo = dstType.GetProperty(srcProperty.Name)
If dstProperty IsNot Nothing Then
If dstProperty.PropertyType.IsAssignableFrom(srcProperty.PropertyType) = True Then
dstProperty.SetValue(dst, srcProperty.GetValue(src, Nothing), Nothing)
End If
End If
Next
End Sub
End Module
Module Module1
Class base_class
Dim _bval As Integer
Public Property bval() As Integer
Get
Return _bval
End Get
Set(ByVal value As Integer)
_bval = value
End Set
End Property
End Class
Class derived_class
Inherits base_class
Public _dval As Integer
Public Property dval() As Integer
Get
Return _dval
End Get
Set(ByVal value As Integer)
_dval = value
End Set
End Property
End Class
Sub Main()
' NARROWING CONVERSION TEST
Dim b As New base_class
b.bval = 10
Dim d As derived_class
'd = CType(b, derived_class) ' invalidcast exception
'd = DirectCast(b, derived_class) ' invalidcast exception
'd = TryCast(b, derived_class) ' returns 'nothing' for c
d = New derived_class
CopyProperties(d, b)
d.dval = 20
Console.WriteLine(b.bval)
Console.WriteLine(d.bval)
Console.WriteLine(d.dval)
Console.ReadLine()
End Sub
End Module
बेशक यह वास्तव में कास्टिंग नहीं है। यह एक नई व्युत्पन्न वस्तु का निर्माण कर रहा है और माता-पिता से गुणों की नकल कर रहा है, जिससे बाल गुण खाली हो गया है। मुझे बस इतना ही करना है और यह आपको लगता है कि आपको करना चाहिए। ध्यान दें कि यह केवल संपत्तियों की नकल करता है, न कि सदस्यों (सार्वजनिक चर) वर्ग में (लेकिन आप इसे यह करने के लिए बढ़ा सकते हैं कि यदि आप सार्वजनिक सदस्यों को उजागर करने के लिए शर्मिंदा हैं)।
सामान्य रूप से कास्टिंग 2 चर बनाता है जो एक ही वस्तु की ओर इशारा करता है (मिनी ट्यूटोरियल यहाँ, कृपया मुझ पर कोने मामले अपवाद न फेंकें)। इस (पाठक के लिए व्यायाम) के लिए महत्वपूर्ण प्रभाव हैं!
निश्चित रूप से मुझे कहना होगा कि क्यों अस्थिर आपको आधार से उदाहरण प्राप्त करने की अनुमति नहीं देता है, लेकिन दूसरे तरीके से करता है। एक ऐसे मामले की कल्पना करें जहां आप वाइनफॉर्म टेक्स्टबॉक्स (व्युत्पन्न) का एक उदाहरण ले सकते हैं और इसे Winforms नियंत्रण के प्रकार में स्टोर कर सकते हैं। बेशक 'नियंत्रण' ऑब्जेक्ट को ओके के चारों ओर ले जा सकता है और आप टेक्स्टबॉक्स के बारे में सभी 'कंट्रोलर-वाई' चीजों से निपट सकते हैं (उदाहरण के लिए, शीर्ष, बाएं, .text गुण)। पाठ बॉक्स विशिष्ट सामग्री (जैसे, .multiline) को स्मृति में पाठ बॉक्स की ओर इशारा करते हुए 'नियंत्रण' प्रकार चर को डाले बिना नहीं देखा जा सकता है, लेकिन यह अभी भी स्मृति में है।
अब कल्पना करें, आपके पास एक नियंत्रण है, और आप इसे टाइप टेक्स्टबॉक्स के एक चर के मामले में चाहते हैं। मेमोरी में कंट्रोल 'मल्टीलाइन' और अन्य टेक्स्टबॉक्स वाली चीजें गायब हैं। यदि आप उन्हें संदर्भित करने का प्रयास करते हैं, तो नियंत्रण जादुई रूप से एक बहु-संपत्ति नहीं होगा! संपत्ति (यहां इसे एक सदस्य चर की तरह देखें, जो वास्तव में एक मूल्य संग्रहीत करता है - क्योंकि पाठ बॉक्स की मेमोरी में है) मौजूद होना चाहिए । जब से आप कास्टिंग कर रहे हैं, याद रखें, यह वही ऑब्जेक्ट होना चाहिए जो आप इंगित कर रहे हैं। इसलिए यह एक भाषा प्रतिबंध नहीं है, इस तरह से मामले में दार्शनिक रूप से असंभव है।
मेरे लिए बेस क्लास से लेकर पैरंट्स तक सभी प्रॉपर्टी फील्ड को इस तरह कॉपी करना काफी था:
using System.Reflection;
public static ChildClass Clone(BaseClass b)
{
ChildClass p = new ChildClass(...);
// Getting properties of base class
PropertyInfo[] properties = typeof(BaseClass).GetProperties();
// Copy all properties to parent class
foreach (PropertyInfo pi in properties)
{
if (pi.CanWrite)
pi.SetValue(p, pi.GetValue(b, null), null);
}
return p;
}
किसी भी वस्तु के लिए एक सार्वभौमिक समाधान यहां पाया जा सकता है
C # 7.0 के अनुसार, आप ऐसा करने के लिए कीवर्ड का उपयोग कर सकते हैं :
परिभाषित उन वर्गों के साथ:
class Base { /* Define base class */ }
class Derived : Base { /* Define derived class */ }
आप तब कुछ कर सकते हैं जैसे:
void Funtion(Base b)
{
if (b is Derived d)
{
/* Do something with d which is now a variable of type Derived */
}
}
जो इसके बराबर होगा:
void Funtion(Base b)
{
Defined d;
if (b is Derived)
{
d = (Defined)b;
/* Do something with d */
}
}
अब आप कॉल कर सकते हैं:
Function(new Derived()); // Will execute code defined in if
साथ ही साथ
Function(new Base()); // Won't execute code defined in if
इस तरह से आप यह सुनिश्चित कर सकते हैं कि आपका डाउनकास्ट वैध होगा और अपवाद नहीं फेंकेगा!
कास्ट करने के लिए, वास्तविक ऑब्जेक्ट एक प्रकार का होना चाहिए या उस प्रकार से प्राप्त किया जाना चाहिए जिस प्रकार से आप कास्ट करने का प्रयास कर रहे हैं ...
या, इसे विपरीत तरीके से बताने के लिए, आप जिस प्रकार कास्ट करने का प्रयास कर रहे हैं, वह उसी प्रकार का होना चाहिए, या ऑब्जेक्ट का वास्तविक आधार।
यदि आपकी वास्तविक वस्तु प्रकार बेसकलेस की है , तो आप इसे एक व्युत्पन्न वर्ग प्रकार में नहीं डाल सकते हैं ...
ServiceStack का उपयोग करने वालों के लिए क्रमिक दृष्टिकोण पर भिन्नता:
var child = baseObject.ConvertTo<ChildType>();
या अधिक क्रिया:
var child = baseObject.ToJson().FromJson<ChildType>();
सर्विसस्टैक का क्रमांकन सुपर फास्ट और सभी हो सकता है, लेकिन स्पष्ट रूप से, यह कम-विलंबता स्थानान्तरण में बड़े पैमाने पर रूपांतरण का समाधान नहीं है, न ही अत्यधिक जटिल प्रकारों के लिए। ServiceStack का उपयोग करने वाले किसी के लिए भी यह स्पष्ट है, लेकिन मैंने टिप्पणी की प्रत्याशा में स्पष्ट किया था।