मैं इस प्रश्न को सीधे जेफरी रिचटर को लिखूंगा, लेकिन पिछली बार उसने मुझे जवाब नहीं दिया :) इसलिए मैं आपकी मदद से जवाब पाने का प्रयास करूंगा :) दोस्तों :)क्या गैर-वर्चुअल विधि कॉल के आंतरिक भाग का वर्णन करते समय रिचटर गलत है?
पुस्तक में "सीएलआर के माध्यम से सी # ", 3 संस्करण, p.108 पर, जेफरी लिखते हैं:
void M3() {
Employee e;
e = new Manager();
year = e.GetYearsEmployed();
...
}
एम 3 में कोड की अगली पंक्ति कॉल कर्मचारी का nonvirtual उदाहरण GetYearsEmployed विधि। को एक गैर-वर्चुअल इंस्टेंस विधि पर कॉल करते समय, JIT कंपाइलर टाइप ऑब्जेक्ट को रेखांकित करता है जो कॉल करने के लिए उपयोग किए जाने वाले चर के प्रकार से मेल खाता है। इस मामले में, परिवर्तनीय ई कर्मचारी के रूप में परिभाषित किया गया है। ( कर्मचारी प्रकार विधि को परिभाषित नहीं किया बुलाया जा रहा है, तो JIT कम्पाइलर चलता वस्तु की ओर वर्ग पदानुक्रम इस विधि की तलाश में नीचे। यह इस कर सकते हैं, क्योंकि प्रत्येक प्रकार वस्तु उस में एक क्षेत्र है कि इसके आधार प्रकार को संदर्भित करता है;। इस जानकारी आंकड़ों में नहीं दिखाया गया है) फिर, JIT कम्पाइलर JITs विधि स्थित प्रकार वस्तु की विधि तालिका में प्रवेश कि विधि को संदर्भित करता है बुलाया जा रहा है, (यदि आवश्यक), और फिर JITted कोड पर कॉल करें।
जब मैं यह पहली बार मैंने सोचा था कि यह वर्ग पदानुक्रम JIT-टिंग दौरान विधि की तलाश में साथ चलने के लिए प्रभावी नहीं होगा पढ़ें। संकलन चरण पर पहले से ही विधि को ढूंढना आसान है। लेकिन मैं जेफरी का मानना था। मैंने इस जानकारी को किसी अन्य मंच पर पोस्ट किया और दूसरे व्यक्ति ने मेरे संदेह की पुष्टि की कि यह अजीब है और यह अप्रभावी होगा और ऐसा लगता है कि यह गलत जानकारी है।
और वास्तव में, यदि आप एक डीकंपेलर में संबंधित आईएल कोड की तलाश करते हैं, जैसे कि आईएलडीएएसएम या रिफ्लेक्टर (मैंने दोनों में चेक किया है) तो आप देखेंगे कि आईएल में कॉल क्लार्ट निर्देश है जो बेस क्लास से विधि को बुला रहा है, इसलिए
public class EmployeeBase
{
public int GetYearsEmployed() { return 1; }
}
public class Employee : EmployeeBase
{
public void SomeOtherMethod() { }
}
public class Manager : Employee
{
public void GenProgressReport() { }
}
...
Employee e;
e = new Manager();
int years = e.GetYearsEmployed();
परिणामस्वरूप आईएल है:
L_0000: nop
L_0001: newobj instance void TestProj.Form1/Manager::.ctor()
L_0006: stloc.0
L_0007: ldloc.0
L_0008: callvirt instance int32 TestProj.Form1/EmployeeBase::GetYearsEmployed()
तुम देखो JIT देखने के लिए कौन सी क्लास में विधि क्रम में स्थित है की जरूरत नहीं है? कंपाइलर को पहले ही पता चला है कि विधि कर्मचारी वर्ग में नहीं है, लेकिन कर्मचारीबेस कक्षा में और एक सही कॉल उत्सर्जित किया गया है। लेकिन रिक्टर के शब्दों से जेआईटी को यह पता लगाना होगा कि विधि वास्तव में रनटाइम पर कर्मचारीबेस कक्षा में स्थित है।
क्या जेफरी रिक्टर ने गलत किया? या मुझे कुछ समझ में नहीं आता?
कोई दूसरे को बाहर नहीं करता है, संकलक जिटर को आसान बनाने के लिए काम करने का हकदार है। Iexe को excompile करने के लिए ildasm.exe का उपयोग करें, कॉल को संशोधित करें और ilasm.exe के साथ वापस संकलित करें। यह अभी भी काम करता है। –
@colinfang - इसके विपरीत, एक व्युत्पन्न कक्षा के लिए विधि टोकन प्राप्त करना संभव है भले ही विधियों को बेस क्लास पर घोषित किया गया हो। इस तरह के तरीकों पर कॉल करना विशेष रूप से सीएलआर स्पेक में कहा जाता है (कम से कम, 'कॉल' ओपोड के लिए; मुझे कोई संकेत नहीं दिखता कि 'कॉलवर्ट' अलग है)। 'आधार' कॉल के लिए, यह वास्तव में पुस्तकालयों को संस्करणित करते समय "भंगुर आधार वर्ग" समस्या को रोक सकता है, और तर्कसंगत रूप से सी # कंपाइलर को इस तरह से कॉल करना चाहिए, हालांकि ऐसा नहीं है। Http://blogs.msdn.com/b/ericlippert/archive/2010/03/29/putting-a-base-in-the-middle.aspx देखें। – kvb
@kvb आपकी टिप्पणी मूल्यवान है और मेरा दूसरा बार प्रयोग (इस बार JustDecompile के लिए प्लगइन की बजाय ilasm का उपयोग करें) साबित हुआ कि आप सही हैं। हालांकि, मैं ईसीएमए 335 में कहीं भी नहीं मिला था। 1. स्पष्ट रूप से एक व्युत्पन्न वर्ग के लिए एक विधि टोकन के अस्तित्व को बताता है जहां आधार वर्ग पर विधियों को घोषित किया जाता है (मुझे विश्वास था कि यह इस्लाम के लॉग के आधार पर 'मेथड्रफ' होगा)। – colinfang