मैं हाल ही में प्रदाताओं के साथ काम कर रहा हूं, और मैं एक दिलचस्प स्थिति में आया हूं जहां मैं एक सार वर्ग रखना चाहता था जिसमें एक सार स्थिर विधि थी। मैं विषय पर कुछ पोस्ट पढ़ता हूं, और यह एक तरह से बना हुआ अर्थ है, लेकिन क्या एक अच्छी व्याख्या है?
मैं हाल ही में प्रदाताओं के साथ काम कर रहा हूं, और मैं एक दिलचस्प स्थिति में आया हूं जहां मैं एक सार वर्ग रखना चाहता था जिसमें एक सार स्थिर विधि थी। मैं विषय पर कुछ पोस्ट पढ़ता हूं, और यह एक तरह से बना हुआ अर्थ है, लेकिन क्या एक अच्छी व्याख्या है?
जवाबों:
स्थैतिक तरीकों को तत्काल नहीं दिया जाता है, वे सिर्फ एक वस्तु संदर्भ के बिना उपलब्ध हैं।
एक स्थिर विधि के लिए एक कॉल क्लास के नाम के माध्यम से किया जाता है, एक वस्तु संदर्भ के माध्यम से नहीं, और इंटरमीडिएट भाषा (आईएल) कोड को कॉल करने के लिए सार विधि को उस वर्ग के नाम के माध्यम से कॉल किया जाएगा जिसने इसे परिभाषित किया है, जरूरी नहीं कि नाम वह वर्ग जिसका आपने उपयोग किया था।
मुझे एक उदाहरण दिखाते हैं।
निम्नलिखित कोड के साथ:
public class A
{
public static void Test()
{
}
}
public class B : A
{
}
यदि आप B.Test, को इस तरह कहते हैं:
class Program
{
static void Main(string[] args)
{
B.Test();
}
}
फिर मुख्य विधि के अंदर वास्तविक कोड इस प्रकार है:
.entrypoint
.maxstack 8
L0000: nop
L0001: call void ConsoleApplication1.A::Test()
L0006: nop
L0007: ret
जैसा कि आप देख सकते हैं, कॉल A.Test को किया जाता है, क्योंकि यह ए क्लास था जिसने इसे परिभाषित किया था, और बी.टेस्ट को नहीं, भले ही आप उस तरह से कोड लिख सकते हैं।
यदि आपके पास वर्ग प्रकार हैं , जैसे डेल्फी में, जहां आप एक प्रकार का संदर्भ देते हुए एक चर बना सकते हैं और एक वस्तु नहीं, तो आपके पास आभासी के लिए अधिक उपयोग होगा और इस प्रकार अमूर्त स्थिर तरीके (और कंस्ट्रक्टर भी) होंगे, लेकिन वे उपलब्ध नहीं हैं और इस प्रकार स्थिर कॉल .NET में गैर-आभासी हैं।
मुझे एहसास है कि IL डिज़ाइनर B.Test को कॉल करने के लिए कोड को संकलित करने की अनुमति दे सकते हैं, और रनटाइम पर कॉल को हल कर सकते हैं, लेकिन यह अभी भी आभासी नहीं होगा, क्योंकि आपको अभी भी वहां किसी प्रकार का वर्ग नाम लिखना होगा।
वर्चुअल मेथड्स, और इस प्रकार एब्सट्रैक्ट, केवल तभी उपयोगी होते हैं जब आप एक वैरिएबल का उपयोग कर रहे होते हैं, जो रनटाइम के दौरान, कई अलग-अलग प्रकार की ऑब्जेक्ट्स को शामिल कर सकते हैं, और आप इस प्रकार वेरिएबल में मौजूद करंट ऑब्जेक्ट के लिए सही मेथड को कॉल करना चाहते हैं। स्थिर तरीकों से आपको किसी भी वर्ग के नाम से गुजरने की आवश्यकता होती है, इसलिए कॉल करने का सटीक तरीका संकलन समय पर जाना जाता है क्योंकि यह बदल नहीं सकता है।
इस प्रकार, .NET में वर्चुअल / एब्स्ट्रैक्ट स्टैटिक मेथड उपलब्ध नहीं हैं।
Test()
में है A
सार और संभवतः में परिभाषित किया जा रहा है के बजाय B
\।
Car
वर्चुअल स्टैटिक CreateFromDescription
फ़ैक्टरी विधि के साथ एक प्रकार होता है , तो कोड जो एक- Car
प्रकार के जेनरिक प्रकार T
को स्वीकार करता है T.CreateFromDescription
, प्रकार की कार बनाने के लिए कॉल कर सकता है T
। इस तरह के एक निर्माण को सीएलआर के भीतर बहुत अच्छी तरह से समर्थित किया जा सकता है यदि प्रत्येक प्रकार जो इस तरह की विधि को परिभाषित करता है एक नेस्टेड क्लास जेनेरिक का एक स्थिर सिंगलटन उदाहरण होता है जो आभासी "स्थिर" विधियों का आयोजन करता है।
स्थैतिक विधियों को विरासत में या अधिग्रहित नहीं किया जा सकता है, और यही कारण है कि वे सार नहीं हो सकते हैं। चूँकि स्थैतिक विधियाँ प्रकार पर परिभाषित होती हैं, उदाहरण के लिए नहीं, एक वर्ग के रूप में, उन्हें उस प्रकार पर स्पष्ट रूप से कहा जाना चाहिए। इसलिए जब आप चाइल्ड क्लास पर एक विधि को कॉल करना चाहते हैं, तो आपको इसे कॉल करने के लिए इसके नाम का उपयोग करने की आवश्यकता है। इससे वंशानुक्रम अप्रासंगिक हो जाता है।
मान लें कि आप एक पल के लिए स्थैतिक तरीकों को अपना सकते हैं। इस परिदृश्य की कल्पना करें:
public static class Base
{
public static virtual int GetNumber() { return 5; }
}
public static class Child1 : Base
{
public static override int GetNumber() { return 1; }
}
public static class Child2 : Base
{
public static override int GetNumber() { return 2; }
}
यदि आप Base.GetNumber () कहते हैं, तो किस विधि को कहा जाएगा? कौन सा मान लौटा? यह देखने के लिए बहुत आसान है कि वस्तुओं के उदाहरणों को बनाए बिना, वंशानुक्रम कठिन है। वंशानुक्रम के बिना सार विधियां सिर्फ ऐसी विधियां हैं जिनमें शरीर नहीं है, इसलिए इसे नहीं बुलाया जा सकता है।
int DoSomething<T>() where T:Base {return T.GetNumber();}
। यह उपयोगी लगता है अगर DoSomething<Base>()
पांच लौट सकते हैं, जबकि DoSomething<Child2>()
दो वापस आ जाएंगे। इस तरह की क्षमता न केवल खिलौने के उदाहरणों के लिए उपयोगी होगी, बल्कि कुछ ऐसी चीज़ों के लिए भी होगी class Car {public static virtual Car Build(PurchaseOrder PO);}
, जहाँ से प्राप्त होने वाली प्रत्येक कक्षा Car
को एक पद्धति को परिभाषित करना होगा, जो खरीद ऑर्डर दिए गए उदाहरण का निर्माण कर सकती है।
एक अन्य प्रतिवादी (मैकडॉवेल) ने कहा कि बहुरूपता केवल वस्तु उदाहरण के लिए काम करता है। वह योग्य होना चाहिए; ऐसी भाषाएं हैं जो कक्षाओं को "क्लास" या "मेटाक्लास" प्रकार के उदाहरणों के रूप में मानते हैं। ये भाषाएं उदाहरण और वर्ग (स्थिर) तरीकों के लिए बहुरूपता का समर्थन करती हैं।
C #, जावा और C ++ से पहले, ऐसी भाषा नहीं है; static
कीवर्ड निरूपित करने के लिए है कि विधि स्थिर-बाध्य है की बजाय गतिशील / आभासी स्पष्ट रूप से प्रयोग किया जाता है।
यहाँ एक ऐसी स्थिति है जहाँ निश्चित रूप से स्थैतिक क्षेत्रों और विधियों के लिए विरासत की आवश्यकता है:
abstract class Animal
{
protected static string[] legs;
static Animal() {
legs=new string[0];
}
public static void printLegs()
{
foreach (string leg in legs) {
print(leg);
}
}
}
class Human: Animal
{
static Human() {
legs=new string[] {"left leg", "right leg"};
}
}
class Dog: Animal
{
static Dog() {
legs=new string[] {"left foreleg", "right foreleg", "left hindleg", "right hindleg"};
}
}
public static void main() {
Dog.printLegs();
Human.printLegs();
}
//what is the output?
//does each subclass get its own copy of the array "legs"?
legs
एक स्थिर अमूर्त संपत्ति होनी चाहिए।
पिछली व्याख्याओं में जोड़ने के लिए, स्थिर विधि कॉल संकलन-समय पर एक विशिष्ट विधि से बाध्य होती है , जो बहुरूपता व्यवहार को नियंत्रित करती है।
हम वास्तव में स्थिर तरीकों (डेल्फी में) से आगे निकल जाते हैं, यह थोड़ा बदसूरत है, लेकिन यह हमारी जरूरतों के लिए ठीक काम करता है।
हम इसका उपयोग करते हैं इसलिए कक्षाओं में बिना वर्ग उदाहरण के उनकी उपलब्ध वस्तुओं की एक सूची हो सकती है, उदाहरण के लिए, हमारे पास एक तरीका है जो इस तरह दिखता है:
class function AvailableObjects: string; override;
begin
Result := 'Object1, Object2';
end;
यह बदसूरत है लेकिन आवश्यक है, इस तरह से हम सिर्फ जरूरत की वस्तुओं को खोज सकते हैं, बजाय इसके कि सभी वर्ग तत्काल उपलब्ध वस्तुओं की खोज करने के लिए तुरंत तैयार हों।
यह एक सरल उदाहरण था, लेकिन एप्लिकेशन स्वयं एक क्लाइंट-सर्वर एप्लिकेशन है, जिसमें सभी कक्षाएं सिर्फ एक सर्वर में उपलब्ध हैं, और कई अलग-अलग क्लाइंट्स को सर्वर की जरूरत की हर चीज की जरूरत नहीं पड़ सकती है और उन्हें कभी भी ऑब्जेक्ट इंस्टेंस की आवश्यकता नहीं होगी।
इसलिए प्रत्येक क्लाइंट के लिए एक अलग सर्वर एप्लिकेशन होने से इसे बनाए रखना बहुत आसान है।
आशा है कि उदाहरण स्पष्ट था।
अमूर्त तरीके अंतर्निहित आभासी हैं। अमूर्त तरीकों के लिए एक उदाहरण की आवश्यकता होती है, लेकिन स्थिर विधियों में एक उदाहरण नहीं होता है। तो, आपके पास एक अमूर्त वर्ग में एक स्थिर विधि हो सकती है, यह सिर्फ स्थिर सार (या सार स्थिर) नहीं हो सकती है।