क्या C # में एक्सटेंशन गुण हैं?


768

क्या C # में एक्सटेंशन गुण हैं?

उदाहरण के लिए, क्या मैं एक एक्सटेंशन प्रॉपर्टी को DateTimeFormatInfoकॉल कर सकता हूं ShortDateLongTimeFormatजो वापस आ जाएगी ShortDatePattern + " " + LongTimePattern?


14
मैं Nullable <T> पर IsNull नामक एक विस्तार विधि जोड़ना चाहता था, जो अभी वापस आएगी! HasValue। .IsNull () निश्चित रूप से बहुत कम है। 19N
केन 19

1
मुझे यह ?
ट्रिनरी

2
मैं चाहता था कि यह जावा की नकल करे enumजो गुण और विधियाँ हो सकती है। C # के enumगुण या विधियाँ नहीं हो सकती हैं, लेकिन आप उन पर विस्तार विधियाँ बना सकते हैं। यह प्रश्न मेरे लिए उपयोगी था, और इसे बंद नहीं किया जाना चाहिए।
इयान मैक्लेयर

हालाँकि, जैसा कि कई लोगों ने कहा है, इस भाषा को जोड़ने के लिए वर्तमान में कोई योजना नहीं है, कोई कारण नहीं है कि यह नहीं किया जा सकता है। तथ्य यह है कि एफ # में न केवल विस्तार गुण हैं, बल्कि स्थैतिक एक्सटेंशन भी हैं जो यह साबित करते हैं कि यह कम से कम एक अच्छा विचार है।
रिचीबन

2
वहाँ बनाया जाना चाहिए
Rootel

जवाबों:


365

फिलहाल यह रोसलिन संकलक द्वारा बॉक्स से बाहर समर्थित नहीं है ...

अब तक, एक्सटेंशन गुण C # मानक के पिछले संस्करणों में शामिल किए जाने के लिए पर्याप्त मूल्यवान नहीं देखे गए थे। C # 7 और C # 8.0 ने इसे प्रस्ताव चैंपियन के रूप में देखा है, लेकिन यह अभी तक जारी नहीं किया गया था, क्योंकि सभी में से अधिकांश यदि पहले से ही एक कार्यान्वयन है, तो वे इसे शुरू से ही सही बनाना चाहते हैं।

लेकिन यह होगा ...

C # 7 कार्य सूची में एक एक्सटेंशन सदस्य आइटम है, इसलिए निकट भविष्य में इसका समर्थन किया जा सकता है। संबंधित संपत्ति की वर्तमान स्थिति Github पर संबंधित मद के तहत पाई जा सकती है ।

हालांकि, एक और भी अधिक आशाजनक विषय है, जो विशेष रूप से गुणों और स्थिर वर्गों या यहां तक ​​कि क्षेत्रों पर ध्यान देने के साथ "सब कुछ का विस्तार" है

इसके अलावा आप एक वैकल्पिक हल का उपयोग कर सकते हैं

जैसा कि इस लेख में निर्दिष्ट किया गया है , आप TypeDescriptorरनटाइम पर किसी ऑब्जेक्ट उदाहरण के लिए एक विशेषता संलग्न करने की क्षमता का उपयोग कर सकते हैं । हालांकि, यह मानक गुणों के सिंटैक्स का उपयोग नहीं कर रहा है।
यह सिंटैक्टिक शुगर से थोड़ा अलग है, एक विस्तारित संपत्ति को परिभाषित करने की संभावना को बढ़ाता है जैसे
string Data(this MyClass instance)विस्तार विधि के लिए एक उपनाम के
string GetData(this MyClass instance)रूप में क्योंकि यह डेटा को कक्षा में संग्रहीत करता है।

मुझे उम्मीद है कि C # 7 एक पूर्ण विशेषताओं वाला सब कुछ (गुण और क्षेत्र) प्रदान करेगा, हालांकि उस बिंदु पर, केवल समय ही बताएगा।

और योगदान करने के लिए स्वतंत्र महसूस करें क्योंकि कल का सॉफ्टवेयर समुदाय से आएगा।

अपडेट: अगस्त २०१६

डॉटनेट टीम ने प्रकाशित किया कि C # 7.0 में नया क्या है और मैड्स टॉर्गेंसन की एक टिप्पणी से :

विस्तार गुण: हमारे पास एक शानदार (शानदार!) इंटर्न गर्मियों में प्रयोग के रूप में लागू होता है, साथ ही साथ अन्य प्रकार के विस्तार सदस्य भी होते हैं। हम इसमें रुचि रखते हैं, लेकिन यह एक बड़ा बदलाव है और हमें विश्वास करने की आवश्यकता है कि यह इसके लायक है।

ऐसा लगता है कि विस्तार गुण और अन्य सदस्य, अभी भी रोज़लिन के भविष्य के रिलीज में शामिल होने के लिए अच्छे उम्मीदवार हैं, लेकिन शायद 7.0 नहीं।

अपडेट: मई २०१ May

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

अपडेट: अगस्त, 2017 - सी # 8.0 प्रस्तावित सुविधा

हालांकि यह अभी भी केवल एक प्रस्तावित विशेषता बनी हुई है , अब हमारे पास एक स्पष्ट दृष्टिकोण है कि इसका सिंटैक्स क्या होगा। ध्यान रखें कि यह विस्तार विधियों के लिए भी नया वाक्यविन्यास होगा:

public interface IEmployee 
{
    public decimal Salary { get; set; }
}

public class Employee
{
    public decimal Salary { get; set; }
}

public extension MyPersonExtension extends Person : IEmployee
{
    private static readonly ConditionalWeakTable<Person, Employee> _employees = 
        new ConditionalWeakTable<Person, Employee>();


    public decimal Salary
    {
        get 
        {
            // `this` is the instance of Person
            return _employees.GetOrCreate(this).Salary; 
        }
        set 
        {
            Employee employee = null;
            if (!_employees.TryGetValue(this, out employee)
            {
                employee = _employees.GetOrCreate(this);
            }
            employee.Salary = value;
        }
    }
}

IEmployee person = new Person();
var salary = person.Salary;

आंशिक कक्षाओं के समान, लेकिन एक अलग विधानसभा में एक अलग वर्ग / प्रकार के रूप में संकलित। ध्यान दें कि आप स्थैतिक सदस्यों और ऑपरेटरों को भी इस तरह से जोड़ पाएंगे। जैसा कि मैड्स टॉर्गेनसेन पॉडकास्ट में उल्लेख किया गया है , विस्तार में कोई भी राज्य नहीं होगा (इसलिए यह निजी उदाहरण के सदस्यों को कक्षा में नहीं जोड़ सकता है) जिसका अर्थ है कि आप उदाहरण से जुड़े निजी इंस्टेंस डेटा को जोड़ने में सक्षम नहीं होंगे । इसका कारण यह है कि यह आंतरिक रूप से शब्दकोशों का प्रबंधन करने के लिए होगा और यह मुश्किल हो सकता है (स्मृति प्रबंधन, आदि ...)। इसके लिए, आप अभी भी पहले बताई गई TypeDescriptor/ ConditionalWeakTableतकनीक का उपयोग कर सकते हैं और संपत्ति के विस्तार के साथ, इसे एक अच्छी संपत्ति के तहत छुपा सकते हैं।

सिंटैक्स अभी भी परिवर्तन के अधीन है जैसा कि इस मुद्दे का तात्पर्य है । उदाहरण के लिए, extendsप्रतिस्थापित किया जा सकता है forजिससे कुछ अधिक प्राकृतिक और कम जावा संबंधित महसूस कर सकते हैं।

दिसंबर 2018 अपडेट करें - रोल्स, एक्सटेंशन और स्थिर इंटरफ़ेस सदस्य

एक्सटेंशन सब कुछ इसे C # 8.0 करने के लिए नहीं बना, क्योंकि कुछ कमियों के कारण इस GitHub टिकट के अंत के रूप में समझाया गया था । इसलिए, डिजाइन में सुधार करने के लिए एक खोज की गई थी। यहाँ , मैड्स टॉर्गेंसन बताते हैं कि भूमिकाएँ और विस्तार क्या हैं और वे कैसे अलग हैं:

रोल्स किसी दिए गए प्रकार के विशिष्ट मूल्यों पर इंटरफेस को लागू करने की अनुमति देते हैं। एक्सटेंशन किसी विशेष प्रकार के कोड के भीतर दिए गए सभी प्रकारों पर इंटरफेस को लागू करने की अनुमति देते हैं।

इसे दो उपयोग मामलों में पिछले प्रस्ताव के विभाजन पर देखा जा सकता है। विस्तार के लिए नई वाक्य रचना इस तरह होगा:

public extension ULongEnumerable of ulong
{
    public IEnumerator<byte> GetEnumerator()
    {
        for (int i = sizeof(ulong); i > 0; i--)
        {
            yield return unchecked((byte)(this >> (i-1)*8));
        }
    }
}

तब आप ऐसा कर पाएंगे:

foreach (byte b in 0x_3A_9E_F1_C5_DA_F7_30_16ul)
{
    WriteLine($"{e.Current:X}");
}

और एक स्थिर इंटरफ़ेस के लिए :

public interface IMonoid<T> where T : IMonoid<T>
{
    static T operator +(T t1, T t2);
    static T Zero { get; }
}

पर एक विस्तार संपत्ति जोड़ें intऔर इलाज के intरूप में IMonoid<int>:

public extension IntMonoid of int : IMonoid<int>
{
    public static int Zero => 0;
}

57
यह सबसे उपयोगी उत्तरों में से एक है जिसका मैंने कभी भी StackExchange पर अनुसरण किया है। लगातार स्थिति के साथ अद्यतन करना और सभी को सूचित करना जो इस पर वापस आते हैं, चर्चा और इतिहास के लिए ठोस लिंक प्रदान करते हैं।
bdrelling

25
यह बहुत अच्छा है कि आप इसे अद्यतित रख रहे हैं - धन्यवाद
डेविड थिएलेन

1
दुर्भाग्य से इस टिप्पणी के अनुसार, भूमिकाएं, एक्सटेंशन और स्टेटिक इंटरफ़ेस के सदस्य केवल C # 11 :( के लिए
Ian केम्प

436

नहीं, वे C # 3.0 में मौजूद नहीं हैं और 4.0 में नहीं जोड़े जाएंगे। यह C # के लिए इच्छित सुविधा की सूची में है, इसलिए इसे भविष्य की तारीख में जोड़ा जा सकता है।

इस बिंदु पर सबसे अच्छा आप कर सकते हैं GetXXX शैली के विस्तार के तरीके।


3
इसी तरह जेनेरिक गुणों के साथ: आपको 'गेटएक्सएक्सएक्सएक्स>>' सिंटैक्स का उपयोग करना होगा।
बजे जय बज़ुजी

3
ठीक है, यही मैंने सोचा था। @ जय, हाँ, मुझे भी उससे नफरत है। विशेष रूप से एक जेनेरिक इंडेक्सर की असमर्थता ... आहें
Svish

75
सुविधा की सूची के लिए लिंक चाहता है?
दान एस्पेरज़ा

2
संस्करण 6.0 और 7.0 के बारे में क्या?
फॉक

2
2020 तक इस पर कोई अपडेट?
चाड

265

नहीं, वे मौजूद नहीं हैं।

मुझे पता है कि सी # टीम उन्हें एक बिंदु पर विचार कर रही थी (या कम से कम एरिक लिपर्ट था) - विस्तार निर्माणकर्ताओं और ऑपरेटरों के साथ (उन लोगों को आपका सिर पाने के लिए थोड़ी देर लग सकती है, लेकिन शांत हैं ...) हालांकि, मैं हेवन किसी भी सबूत नहीं देखा कि वे C # 4 का हिस्सा होंगे।


संपादित करें: वे C # 5 में दिखाई नहीं दिए, और जुलाई 2014 तक ऐसा नहीं लगता कि यह C # 6 में होने वाला है।

एरिक लिपर्ट , नवंबर 2012 में Microsoft के माध्यम से C # संकलक टीम के प्रमुख डेवलपर, ने 2009 के अक्टूबर में इसके बारे में ब्लॉग किया:


2
हां, और वे अभी भी क्षेत्र को छिपा सकते हैं - एक एकल संपत्ति की स्थापना दो गुणों को नीचे या इसके विपरीत सेट कर सकती है। (एक सामान्य आकार की संपत्ति, और चौड़ाई / ऊँचाई विस्तार गुण, या इसके विपरीत के साथ कुछ कल्पना करें।) वे केवल-पढ़ने वाले के रूप में अधिक उपयोगी होंगे, हालांकि, मुझे संदेह है।
जॉन स्कीट

23
आप विस्तार के तरीकों से बंध नहीं सकते हैं ... डेटाबाइंडिंग के लिए अपने गुणों को जोड़ने में सक्षम होना कई स्थितियों में सहायक हो सकता है।
निक

3
@ इलेप्पी - संपत्ति के विस्तार का मूल्य बूल और स्ट्रिंग गुणों को सबसे अधिक लाभ होगा जो मुझे लगता है। से छुटकारा ()अंत में है बहुत अधिक पठनीय। मुझे व्यक्तिगत रूप से पता है, मेरे द्वारा लिखे गए एक्सटेंशन का कम से कम 90% उन 2 प्रकारों का है।
कोड मैवरिक

4
यह क्यों उपयोगी होगा, इसका एक उदाहरण देने के लिए, मेरे पास एक EFCF मॉडल है। कुछ कक्षाओं में मेरे पास केवल-पढ़ने के लिए गुण हैं जो मैं स्वरूपित जानकारी को वापस करने के लिए उपयोग करता हूं: FullName= FirstName + LastName, ShortName= FirstName + LastName[0]। मैं इनमें से अधिक गुणों को जोड़ना चाहूंगा, लेकिन मैं वास्तविक वर्गों को "गंदा" नहीं करना चाहता। इस स्थिति में, एक विस्तार संपत्ति, जो केवल पढ़ने के लिए है, सही है क्योंकि मैं कार्यक्षमता जोड़ सकता हूं, मुख्य वर्ग को साफ रख सकता हूं, और अभी भी उस जानकारी को उजागर कर सकता हूं जिसे मैं यूआई में उजागर करना चाहता हूं।
Gup3rSuR4c

4
@JonSkeet: आप सही कह रहे हैं, मैंने अपनी खुद की क्लास बनाकर जो करना चाहा, उसे खत्म कर दिया, फिर सभी संबंधित सीलबंद क्लास के तरीकों और गुणों को static implicit operator FileInfo(FileInfoEx fex)समेट लिया , फिर जो मेरे निहित फाइलइंफो ऑब्जेक्ट को प्रदान करता है। यह प्रभावी रूप से मुझे FileInfoEx का इलाज करने देता है जैसे कि यह FileInfo से विरासत में मिला है, भले ही वह वर्ग सील हो।
स्टीव एल

27

अपडेट ( इस अपडेट को इंगित करने के लिए @chaost का धन्यवाद ):

Mads Torgersen: "एक्सटेंशन सब कुछ इसे C # 8.0 में नहीं बनाया। यह" पकड़ा गया ", यदि आप, भाषा के आगे के भविष्य के बारे में एक बहुत ही रोमांचक बहस में, और अब हम यह सुनिश्चित करना चाहते हैं कि हम नहीं करें इसे भविष्य की संभावनाओं को बाधित करने वाले तरीके से जोड़ें। कभी-कभी भाषा डिजाइन बहुत लंबा खेल होता है! "

स्रोत: https://blogs.msdn.microsoft.com/dotnet/2018/11/12/building-c-8-0/ में टिप्पणी अनुभाग


मैंने गिनना बंद कर दिया कि मैंने इस प्रश्न को कितनी बार खोला है और उम्मीद है कि इसे लागू किया जाएगा।

खैर, आखिरकार हम सभी खुशी मना सकते हैं! Microsoft इसे अपनी आगामी C # 8 रिलीज़ में पेश करने जा रहा है।

इसलिए ऐसा करने के बजाय ...

public static class IntExtensions
{
   public static bool Even(this int value)
   {
        return value % 2 == 0;
   }
}

हम आखिरकार ऐसा कर पाएंगे ...

public extension IntExtension extends int
{
    public bool Even => this % 2 == 0;
}

स्रोत: https://blog.ndepend.com/c-8-0-features-glprise-future/


3
इस सप्ताह C # 8.0 सुविधाओं की घोषणा की गई थी और मुझे इसमें से कोई भी दुर्भाग्य नहीं दिखाई दिया।
मेटो टोरेस-रुइज़

1
@ MateoTorres-Ruiz 'Mads Torgersen' (C # dev) की एक टिप्पणी, जो किसी से इसके बारे में पूछ रही है (3 दिन पहले): "एक्सटेंशन सब कुछ इसे C # 8.0 में नहीं बनाता था। इसे" पकड़ा गया ", यदि आप करेंगे।" , भाषा के आगे के भविष्य के बारे में एक बहुत ही रोमांचक बहस में, और अब हम यह सुनिश्चित करना चाहते हैं कि हम इसे भविष्य की संभावनाओं को बाधित करने वाले तरीके से न जोड़ें। कभी-कभी भाषा का डिज़ाइन बहुत लंबा खेल होता है! " बुरा लगता है .. (इसे कोरमिम्स लिंक पर, टिप्पणी अनुभाग में पढ़ें)
चोस्ट नोव

8

जैसा कि @Pononity में उल्लेख किया गया है, आप मौजूदा ऑब्जेक्ट्स में प्रॉपर्टीज़ जोड़ने के लिए कंडीशनल वीकटेबल का उपयोग कर सकते हैं। डायनेमिक एक्सपेंडीओबजेक्ट के साथ संयुक्त, आप कुछ लाइनों में डायनेमिक एक्सटेंशन गुण लागू कर सकते हैं:

using System.Dynamic;
using System.Runtime.CompilerServices;

namespace ExtensionProperties
{
    /// <summary>
    /// Dynamically associates properies to a random object instance
    /// </summary>
    /// <example>
    /// var jan = new Person("Jan");
    ///
    /// jan.Age = 24; // regular property of the person object;
    /// jan.DynamicProperties().NumberOfDrinkingBuddies = 27; // not originally scoped to the person object;
    ///
    /// if (jan.Age &lt; jan.DynamicProperties().NumberOfDrinkingBuddies)
    /// Console.WriteLine("Jan drinks too much");
    /// </example>
    /// <remarks>
    /// If you get 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create' you should reference Microsoft.CSharp
    /// </remarks>
    public static class ObjectExtensions
    {
        ///<summary>Stores extended data for objects</summary>
        private static ConditionalWeakTable<object, object> extendedData = new ConditionalWeakTable<object, object>();

        /// <summary>
        /// Gets a dynamic collection of properties associated with an object instance,
        /// with a lifetime scoped to the lifetime of the object
        /// </summary>
        /// <param name="obj">The object the properties are associated with</param>
        /// <returns>A dynamic collection of properties associated with an object instance.</returns>
        public static dynamic DynamicProperties(this object obj) => extendedData.GetValue(obj, _ => new ExpandoObject());
    }
}

एक उपयोग उदाहरण xml टिप्पणियों में है:

var jan = new Person("Jan");

jan.Age = 24; // regular property of the person object;
jan.DynamicProperties().NumberOfDrinkingBuddies = 27; // not originally scoped to the person object;

if (jan.Age < jan.DynamicProperties().NumberOfDrinkingBuddies)
{
    Console.WriteLine("Jan drinks too much");
}

jan = null; // NumberOfDrinkingBuddies will also be erased during garbage collection

सबसे अच्छा जवाब
N73k

1

क्योंकि मुझे हाल ही में इसकी आवश्यकता थी, मैंने उत्तर के स्रोत को देखा:

गुण जोड़कर वर्ग का विस्तार करें

और अधिक गतिशील संस्करण बनाया:

public static class ObjectExtenders
{
    static readonly ConditionalWeakTable<object, List<stringObject>> Flags = new ConditionalWeakTable<object, List<stringObject>>();

    public static string GetFlags(this object objectItem, string key)
    {
        return Flags.GetOrCreateValue(objectItem).Single(x => x.Key == key).Value;
    }

    public static void SetFlags(this object objectItem, string key, string value)
    {
        if (Flags.GetOrCreateValue(objectItem).Any(x => x.Key == key))
        {
            Flags.GetOrCreateValue(objectItem).Single(x => x.Key == key).Value = value;
        }
        else
        {
            Flags.GetOrCreateValue(objectItem).Add(new stringObject()
            {
                Key = key,
                Value = value
            });
        }
    }

    class stringObject
    {
        public string Key;
        public string Value;
    }
}

(यह शायद एक बहुत सुधार किया जा सकता (नामकरण, स्ट्रिंग के बजाय गतिशील), मैं इस समय इस सीएफ 3.5 में एक साथ एक hacky ConditionalWeakTable के साथ उपयोग https://gist.github.com/Jan-WillemdeBruyn/db79dd6fdef7b9845e217958db98c4d4 )


क्षमा करें, लेकिन यद्यपि यह बहुत अच्छी तरह से दिखता है, इसका विस्तार गुणों से कोई लेना-देना नहीं है, लेकिन केवल विस्तार विधियों को दर्शाता है।
वाइकिंग
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.