C # इंटरफ़ेस में फ़ील्ड क्यों नहीं हो सकते?


223

उदाहरण के लिए, मान लें कि मुझे एक ICarइंटरफ़ेस चाहिए और सभी कार्यान्वयन में फ़ील्ड शामिल होगा Year। क्या इसका मतलब यह है कि प्रत्येक कार्यान्वयन को अलग से घोषित करना होगा Year? यह केवल इंटरफ़ेस में इसे परिभाषित करने के लिए अच्छा नहीं होगा?


21
इंटरफेस का कार्यान्वयन नहीं है, इसके लिए एक अमूर्त वर्ग का उपयोग करें, संपत्ति के साथ वर्ष
PostMan

6
यहां जो कहा गया है उसे जोड़ने के लिए, इंटरफेस अनुबंध हैं, और एक फ़ील्ड एक कार्यान्वयन विवरण है जिसमें यह मशीन की मेमोरी में एक स्लॉट को परिभाषित करता है ताकि मूल्य (स्केलर या एड्रेस पॉइंटर) में डाल दिया जा सके।
हर्ज़ेमिस्टर

5
लेकिन अगर क्षेत्र सार्वजनिक है, तो यह अनुबंध का हिस्सा है और न केवल एक कार्यान्वयन विवरण है, है ना?
एलेक्स

जवाबों:


238

हालाँकि, कई अन्य उत्तर सिमेंटिक स्तर पर सही हैं, लेकिन मुझे यह भी दिलचस्प लगता है कि कार्यान्वयन विवरण के स्तर से इस प्रकार के प्रश्नों पर संपर्क करें।

एक इंटरफ़ेस को स्लॉट्स के संग्रह के रूप में सोचा जा सकता है , जिसमें विधियां शामिल हैं । जब एक क्लास एक इंटरफ़ेस लागू करता है, तो क्लास को रनटाइम बताने की आवश्यकता होती है कि सभी आवश्यक स्लॉट कैसे भरें। जब आप कहें

interface IFoo { void M(); } 
class Foo : IFoo { public void M() { ... } }

वर्ग कहता है "जब आप मेरे बारे में एक उदाहरण बनाते हैं, तो IFoo.M के लिए स्लॉट में Foo.M का संदर्भ दें।

तब जब आप कॉल करते हैं:

IFoo ifoo = new Foo();
ifoo.M();

कंपाइलर कोड बनाता है जो कहता है कि "ऑब्जेक्ट से पूछें कि IFoo.M के लिए स्लॉट में क्या विधि है, और उस विधि को कॉल करें।

यदि एक इंटरफ़ेस स्लॉट्स का एक संग्रह होता है जिसमें विधियाँ होती हैं, तो उनमें से कुछ स्लॉट्स में किसी गुण के प्राप्त करने और सेट करने के तरीके, इंडेकर के प्राप्त करने और सेट करने के तरीके और किसी ईवेंट के तरीकों को जोड़ने और हटाने के तरीके शामिल हो सकते हैं। लेकिन एक क्षेत्र एक विधि नहीं है । फ़ील्ड के साथ कोई "स्लॉट" जुड़ा नहीं है जिसे आप फ़ील्ड स्थान के संदर्भ में "भर सकते हैं"। और इसलिए, इंटरफेस विधियों, गुणों, अनुक्रमकों और घटनाओं को परिभाषित कर सकते हैं, लेकिन फ़ील्ड नहीं।


26
एक चीज जो मुझे कभी-कभी याद आती है, वह इंटरफ़ेस-स्तर के स्थिरांक को परिभाषित करने की एक जावा जैसी क्षमता है, जिसे संभवतः भाषा में समर्थन करने के लिए "स्लॉट" की आवश्यकता नहीं होगी।
LBushkin

2
मुझे सरल शब्दों में स्पष्टीकरण पसंद है। धन्यवाद। "C # के माध्यम से CLR" और "आवश्यक .net वॉल्यूम 1" अधिक विवरण प्रदान करते हैं।
संदीप जीबी

6
फ़ील्ड में स्लॉट क्यों नहीं है? और ऑपरेटरों के साथ एक ही सवाल? मुझे याद है कि एक इंटरफेस को कार्यान्वित करने के लिए बतख टाइपिंग के बारे में सुनने के लिए कि क्या एक इंटरफ़ेस लागू किया गया है, भले ही वर्ग को इंटरफ़ेस विरासत में नहीं मिला हो। एक क्षेत्र को खींचने के लिए केंट प्रतिबिंब (या एक स्लॉट) का उपयोग क्यों किया जाता है? मैं अभी भी अपना कोड लिख रहा हूं, इसलिए मुझे फ़ील्ड्स की आवश्यकता नहीं हो सकती है, लेकिन मुझे आश्चर्य है कि मैं ऑपरेटरों का उपयोग नहीं कर सकता हूं। ऑपरेटर बिल्कुल मेरी समझ के तरीकों की तरह हैं सिवाय इसके कि सभी को ओवरलोड नहीं किया जा सकता है (से An interface cannot contain constants, fields, operatorsmsdn.microsoft.com/en-us/library/ms173156.aspx )

@acidzombie: एक इंटरफ़ेस ऑपरेटर को परिभाषित क्यों नहीं कर सकता इसका प्रश्न अलग है (हालांकि शायद संबंधित है) इसमें फ़ील्ड क्यों नहीं हो सकते; यदि आप अभी भी उस में रुचि रखते हैं तो मैं एक और प्रश्न पोस्ट करने का सुझाव दूंगा।
एडम रॉबिन्सन

1
@ b1nary.atr0phy खेतों के साथ क्यों? उदाहरण के लिए, यदि मैंने एक विधि घोषित की है int One(), तो कार्यान्वयन public int One(){return 1;}एक क्षेत्र नहीं है।
Hi-Angel

131

सी # में इंटरफेस का उद्देश्य अनुबंध को परिभाषित करना है जो एक वर्ग का पालन करेगा - एक विशेष कार्यान्वयन नहीं।

उस भावना में, C # इंटरफेस गुणों को परिभाषित करने की अनुमति देते हैं - जिसके लिए कॉलर को एक कार्यान्वयन की आपूर्ति करनी चाहिए:

interface ICar
{
    int Year { get; set; }
}

कार्यान्वयन को आसान बनाने के लिए कक्षाएं लागू करने से ऑटो-संपत्तियों का उपयोग किया जा सकता है, अगर संपत्ति से जुड़ा कोई विशेष तर्क नहीं है:

class Automobile : ICar
{
    public int Year { get; set; } // automatically implemented
}

5
क्या सब कुछ सार्वजनिक नहीं है जो अनुबंध का एक हिस्सा है। यदि किसी वर्ग के पास पब्लिक इंट इयर ईयर है, तो क्या यह नहीं कहता है कि क्लास कॉन्ट्रैक्ट में उस पर उपस्थित होने के लिए टाइप ईयर का एक क्षेत्र है, और सुलभ है?
डिडियर ए।

1
पार्टी के लिए देर हो चुकी है, लेकिन नहीं, इस मामले में इसका मतलब है कि अनुबंध में एक PROPERTY वर्ष है, जिसे किसी भी एबाइडिंग वर्ग को लागू करना चाहिए। गुण वास्तव में प्राप्त / सेट करने के तरीके हैं, जिनके पास बैकिंग फ़ील्ड स्वचालित रूप से उत्पन्न होती है यदि कोई विशेष तर्क की आवश्यकता नहीं है। विशेष सिंटैक्स केवल स्पष्ट संकेतन के लिए है।
user3613916

मैं उस स्वचालित कार्यान्वयन के लिए एक निरंतर डिफ़ॉल्ट मान (123 की तरह) कैसे परिभाषित कर सकता हूं Year?
lama12345

1
@ lama12345 मैं पार्टी के लिए भी देर से आता हूं, लेकिन C # 6 (2015, .NET फ्रेमवर्क 4.6 और .NET कोर) के बाद से आप उस उद्देश्य के लिए ऑटो-प्रॉपर्टी का उपयोग कर सकते हैं। public int Year => 123;। हालाँकि, इस मामले में इसका कोई मतलब नहीं है कि एक सेटर है, इसलिए इंटरफ़ेस को परिभाषित करना होगाint Year { get; }
EriF89

56

इसे एक संपत्ति के रूप में घोषित करें:

interface ICar {
   int Year { get; set; }
}

47
सवाल यह है कि " C # इंटरफेस में फ़ील्ड क्यों नहीं हो सकते?"। यह पता नहीं है।
आकाशवाणी

14
मैं मानता हूं कि यह उत्तर ओपी प्रश्न का उत्तर नहीं देता है, लेकिन ठीक है, इसने मेरी समस्या हल कर दी।
गोर्गेन

36

एरिक लिपर्ट ने इसका उल्लेख किया, मैं यह कहने के लिए एक अलग तरीके का उपयोग करूंगा कि उन्होंने क्या कहा। एक इंटरफ़ेस के सभी सदस्य आभासी हैं और उन्हें उन सभी को एक वर्ग द्वारा अधिलेखित करने की आवश्यकता है जो इंटरफ़ेस को विरासत में लेते हैं। आप इंटरफ़ेस घोषणा में वर्चुअल कीवर्ड को स्पष्ट रूप से नहीं लिखते हैं, और न ही कक्षा में ओवरराइड कीवर्ड का उपयोग करते हैं, वे निहित हैं।

वर्चुअल कीवर्ड .NET में विधियों और तथाकथित v- तालिका, विधि बिंदुओं की एक सरणी के साथ कार्यान्वित किया जाता है। ओवरराइड कीवर्ड एक अलग विधि सूचक के साथ वी-टेबल स्लॉट को भरता है, जो बेस क्लास द्वारा निर्मित एक को ओवरराइट करता है। गुण, घटनाओं और सूचकांक को हुड के तहत तरीकों के रूप में लागू किया जाता है। लेकिन खेत नहीं हैं। इसलिए इंटरफ़ेस में फ़ील्ड नहीं हो सकते हैं।


आपने एरिक द्वारा उल्लिखित स्लॉट की अवधारणा को तकनीकी / वास्तविक नाम (वी-टेबल) प्रदान किया। विस्तार हंस के लिए धन्यवाद।
RBT

यदि वीक्षकों द्वारा डिफ़ॉल्ट कार्यान्वयन को रोक दिया जाता है, तो वि-तालिका का क्या मतलब होगा? यह C # 8.0 में बदलता है, लेकिन यह बिंदु के बगल में है।
एंथनीमनोत्रोसा

19

सिर्फ एक Yearसंपत्ति क्यों नहीं है , जो पूरी तरह से ठीक है?

फ़ील्ड में फ़ील्ड शामिल नहीं हैं क्योंकि फ़ील्ड डेटा प्रतिनिधित्व का एक विशिष्ट कार्यान्वयन का प्रतिनिधित्व करते हैं, और उन्हें उजागर करने से एन्कैप्सुलेशन टूट जाएगा। इस प्रकार एक क्षेत्र के साथ एक इंटरफ़ेस प्रभावी रूप से एक इंटरफ़ेस के बजाय कार्यान्वयन के लिए कोडिंग होगा, जो एक इंटरफ़ेस के लिए एक उत्सुक विरोधाभास है!

उदाहरण के लिए, आपके Yearविनिर्देशन के भाग के लिए यह आवश्यक हो सकता है कि यह ICarकार्यान्वयनकर्ताओं के लिए अमान्य हो, Yearजो वर्तमान वर्ष + 1 या 1900 से पहले असाइनमेंट की अनुमति देता है। यह कहने का कोई तरीका नहीं है कि यदि आपने Yearखेतों को उजागर किया था - तो उपयोग करने के लिए बेहतर है यहाँ काम करने के बजाय गुण।


18

संक्षिप्त उत्तर हां है, प्रत्येक कार्यान्वयन प्रकार को अपना स्वयं का बैकिंग वैरिएबल बनाना होगा। ऐसा इसलिए है क्योंकि एक इंटरफ़ेस एक अनुबंध के अनुरूप है। सभी यह कर सकते हैं कि कोड के विशेष रूप से सार्वजनिक रूप से सुलभ टुकड़े निर्दिष्ट करें कि एक कार्यान्वयन प्रकार को उपलब्ध कराना चाहिए; इसमें कोई भी कोड नहीं हो सकता है।

इस परिदृश्य पर विचार करें कि आप क्या सुझाव देते हैं:

public interface InterfaceOne
{
    int myBackingVariable;

    int MyProperty { get { return myBackingVariable; } }
}

public interface InterfaceTwo
{
    int myBackingVariable;

    int MyProperty { get { return myBackingVariable; } }
}

public class MyClass : InterfaceOne, InterfaceTwo { }

हमारे यहाँ कुछ समस्याएं हैं:

  • क्योंकि एक इंटरफ़ेस के सभी सदस्य हैं - परिभाषा के अनुसार, हमारा बैकिंग वेरिएबल अब इंटरफ़ेस का उपयोग करके किसी के भी सामने आता है
  • कौन सा उपयोग myBackingVariableकरेगा MyClass?

लिया गया सबसे आम तरीका है इंटरफ़ेस को घोषित करना और इसे लागू करने वाले एक नंगे पैर अमूर्त वर्ग। यह आपको अमूर्त वर्ग से विरासत में मिलने वाले लचीलेपन की अनुमति देता है और मुक्त करने के लिए कार्यान्वयन प्राप्त कर रहा है, या स्पष्ट रूप से इंटरफ़ेस को लागू करने और किसी अन्य वर्ग से प्राप्त करने की अनुमति दी जा रही है। यह कुछ इस तरह काम करता है:

public interface IMyInterface
{
    int MyProperty { get; set; }
}

public abstract class MyInterfaceBase : IMyInterface
{
    int myProperty;

    public int MyProperty
    {
        get { return myProperty; }
        set { myProperty = value; }
    }
}

7

दूसरों ने 'क्यों' दिया है, इसलिए मैं सिर्फ इतना जोड़ूंगा कि आपका इंटरफ़ेस नियंत्रण को परिभाषित कर सकता है; यदि आप इसे एक संपत्ति में लपेटते हैं:

public interface IView {
    Control Year { get; }
}


public Form : IView {
    public Control Year { get { return uxYear; } } //numeric text box or whatever
}

3

इंटरफेस में कोई कार्यान्वयन नहीं है।

  1. एक संपत्ति के साथ एक इंटरफेस को परिभाषित करें।
  2. इसके अलावा आप उस इंटरफ़ेस को किसी भी वर्ग में लागू कर सकते हैं और आगे जाने वाले इस वर्ग का उपयोग कर सकते हैं।
  3. यदि आवश्यक हो तो आप इस संपत्ति को कक्षा में आभासी के रूप में परिभाषित कर सकते हैं ताकि आप इसके व्यवहार को संशोधित कर सकें।

3

पहले से ही बहुत कुछ कहा गया है, लेकिन इसे सरल बनाने के लिए, यहाँ मेरा लेना है। इंटरफेस का उद्देश्य उपभोक्ताओं या वर्गों द्वारा लागू किए जाने वाले विधि अनुबंधों और मूल्यों को संग्रहीत करने के लिए फ़ील्ड नहीं रखना है।

आप तर्क दे सकते हैं कि तब संपत्तियों की अनुमति क्यों है? तो सरल उत्तर है - गुणों को आंतरिक रूप से केवल तरीकों के रूप में परिभाषित किया जाता है।


1
यदि आपको किसी सदस्य को एक्सेस करने की आवश्यकता है तो उसे एक संपत्ति बनाएं और आप अच्छे होंगे।
अनोम

0

इसके लिए आपके पास एक कार बेस क्लास हो सकता है जो वर्ष क्षेत्र को लागू करता है, और अन्य सभी कार्यान्वयन इससे विरासत में मिल सकते हैं।


0

एक इंटरफ़ेस सार्वजनिक उदाहरण गुणों और विधियों को परिभाषित करता है । फ़ील्ड आमतौर पर निजी होती हैं, या सबसे अधिक संरक्षित, आंतरिक या संरक्षित आंतरिक (शब्द "फ़ील्ड" आमतौर पर सार्वजनिक रूप से उपयोग नहीं की जाती है)।

जैसा कि अन्य उत्तरों द्वारा कहा गया है कि आप एक आधार वर्ग को परिभाषित कर सकते हैं और एक संरक्षित संपत्ति को परिभाषित कर सकते हैं जो सभी उत्तराधिकारियों द्वारा सुलभ होगी।

एक विषमता यह है कि एक इंटरफ़ेस को वास्तव में आंतरिक के रूप में परिभाषित किया जा सकता है लेकिन यह इंटरफ़ेस की उपयोगिता को सीमित करता है, और इसका उपयोग आमतौर पर आंतरिक कार्यक्षमता को परिभाषित करने के लिए किया जाता है जो अन्य बाहरी कोड द्वारा उपयोग नहीं किया जाता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.