2010-10-01 3 views
8

StringBuilder वर्ग श्रृंखला विधि करने के लिए, आप की अनुमति देता है कि मैं क्या एक बहुत ही सहज तरीके से करने पर विचार में) .Append करने के लिए कॉल (, .AppendFormat() और कुछ अन्य इसलिए की तरह:सी # सूची <T> की सामान्य अधिभार: यह कैसे किया जाएगा?

StringBuilder sb = new StringBuilder(); 
sb.Append("first string") 
    .Append("second string); 

सूची क्लास ' दूसरी तरफ।() विधि, शून्य लौटाती है - इसलिए चेनिंग कॉल काम नहीं करती है। यह मेरी राय में और जेन कोब के अमर शब्द "बस डॉन" कोई दयालु अर्थ नहीं बनाते हैं "।

मैं मानता हूं कि जेनिक्स की मेरी समझ बहुत बुनियादी है, लेकिन मैं .dd() विधि (और अन्य) को अधिभारित करना चाहता हूं ताकि वे मूल वस्तु को वापस कर सकें और चेनिंग की अनुमति दे सकें। किसी भी और सभी सहायता को आगे Firefly उद्धरण के साथ पुरस्कृत किया जाएगा।

उत्तर

13

आप Add विधि के लिए एक ही नाम रखना चाहते हैं, तो आप आधार वर्ग से विधि छिपाने सकता है:

public class MyList<T> : List<T> 
{ 
    public new MyList<T> Add(T item) 
    { 
     base.Add(item); 
     return this; 
    } 
} 

बहरहाल, यह केवल यदि आप एक चर के साथ इस सूची से छेड़छाड़ कर रहे हैं काम करेंगे स्पष्ट रूप से MyList<T> के रूप में टाइप किया गया है (यानी यदि आपका चर IList<T> उदाहरण के लिए घोषित किया गया है तो यह काम नहीं करेगा)। तो मुझे लगता है कि एक्सटेंशन विधि से जुड़े समाधान बेहतर हैं, भले ही इसका मतलब है कि विधि का नाम बदलना।

दूसरों हालांकि पहले से ही विस्तार के तरीकों के साथ समाधान को तैनात किया है, यहाँ एक और एक, संग्रह के वास्तविक प्रकार के संरक्षण का लाभ दिया है कि है:

public static class ExtensionMethods 
{ 
    public static TCollection Append<TCollection, TItem>(this TCollection collection, TItem item) 
     where TCollection : ICollection<TItem> 
    { 
     collection.Add(item); 
     return collection; 
    } 
} 

है जैसे उसे किसी का उपयोग करें:

var list = new List<string>(); 
list.Append("Hello").Append("World"); 
+0

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

2
public static IList<T> Anything-not-Add*<T>(this IList<T> list, T item) 
{ 
    list.Add(item); 
    return list; 
} 

*AddItem, Append, AppendList, आदि (नीचे टिप्पणी देखें)

एक ही विचार की तरह मेरे मन में आए अन्य लोग भी स्वतंत्र रूप से:

public static TList Anything<TList, TItem>(this TList list, TItem item) 
    where TList : IList<TItem> 
{ 
    list.Add(item); 
    return list; 

}

और थॉमस सही है: जहां तक ​​IList<T> विरासत ICollection<T> आपको आईसीओएल का उपयोग करना चाहिए ection।

+1

जीत के लिए एक्सटेंशन विधियां! यह केवल सी # 3 या बाद में काम करेगा (इसलिए वीएस 2008 या 2010)। –

+4

यह काम नहीं करेगा, क्योंकि अधिभार संकल्प संकलक के दौरान – desco

+0

विस्तार करने के लिए उदाहरण विधि पसंद करेंगे यह एक विस्तार विधि है, है ना? कैसे संकलक मूल के बजाय विधि के इस संस्करण का उपयोग करने के पता चल जाएगा –

5

उपयोग विस्तार विधि बना सकते हैं

public static class ListExtensions 
{ 
    public static List<T> AddItem<T>(this List<T> self, T item) 
    { 
     self.Add(item); 
     return self; 
    } 
} 

var l = new List<int>(); 
l.AddItem(1).AddItem(2); 

संपादित

हम भी इस विधि का संग्रह पैरामीटर से अधिक सामान्य बना सकते हैं

public static class ListExtensions 
{ 
    public static TC AddItem<TC, T>(this TC self, T item) 
     where TC : ICollection<T> 
    { 
     self.Add(item); 
     return self; 
    } 
} 

var c1 = new Collection<int>(); 
c1.AddItem(1).AddItem(2); 

var c2 = new List<int>(); 
c2.AddItem(10).AddItem(20); 

संपादित 2: हो सकता है कि किसी को मिलेगा यह चाल उपयोगी है, यह यूटीआई के लिए संभव है संपत्तियों को सेट करने और मौजूदा उदाहरणों में मूल्य जोड़ने के लिए नेस्टेड ऑब्जेक्ट प्रारंभकर्ता और संग्रह प्रारंभकर्ता।

using System; 
using System.Collections.Generic; 
using System.Linq; 

struct I<T> 
{ 
    public readonly T V; 
    public I(T v) 
    { 
     V = v; 
    } 
} 

class Obj 
{ 
    public int A { get; set; } 
    public string B { get; set; } 

    public override string ToString() 
    { 
     return string.Format("A={0}, B={1}", A, B); 
    } 
} 


class Program 
{ 
    static void Main() 
    { 
     var list = new List<int> { 100 }; 
     new I<List<int>>(list) 
      { 
       V = { 1, 2, 3, 4, 5, 6 } 
      }; 

     Console.WriteLine(string.Join(" ", list.Select(x => x.ToString()).ToArray())); // 100 1 2 3 4 5 6 

     var obj = new Obj { A = 10, B = "!!!" }; 
     Console.WriteLine(obj); // A=10, B=!!! 
     new I<Obj>(obj) 
      { 
       V = { B = "Changed!" } 
      }; 
     Console.WriteLine(obj); // A=10, B=Changed! 
    } 
} 
+0

क्या विधि का नाम बदलने के बिना ऐसा करने का कोई तरीका नहीं है? मैं अन्य डेवलपर्स में संभव भ्रम को कम करने –

+0

आप ICollection बजाय सूची

+0

@Thomas के रूप में पैरामीटर की घोषणा करनी चाहिए चाहते हैं: 'जोड़ें()' दोनों IList और ICollection – abatishchev

1

एक विस्तार विधि बंद है: के रूप में अगर एक उदाहरण सदस्य हस्ताक्षर ('जोड़ें' आप पहले से ही के बारे में शिकायत कर रहे हैं से मेल खाता है

public static List<T> Append(this List<T> list, T item) 
{ 
    list.Add(item); 
    return self; 
} 

नोट है कि हम एक नए नाम के साथ उसे बनाने के लिए,) तो विस्तार विधि नहीं कहा जाएगा।

हालांकि, मैं इसके खिलाफ अनुशंसा करता हूं। जबकि मुझे खुद को चेन करना पसंद है, यह सी # पुस्तकालयों में दुर्लभ है, इसका मतलब है कि यह अन्य भाषाओं में नहीं है क्योंकि यह अधिक आम है (इसके लिए कोई तकनीकी कारण नहीं है, हालांकि कुछ अंतर यह है कि गुण कैसे काम करते हैं, यह कुछ अन्य भाषाओं में थोड़ा अधिक प्रोत्साहित करता है , सामान्य बातों के संदर्भ में चीजें हैं)। इस वजह से, यह सक्षम बनाता है जो सी # में कहीं और परिचित नहीं हैं, और आपके कोड को किसी अन्य देव द्वारा गलत तरीके से गलत होने की संभावना है।

0

मुझे एक्सटेंशन दृष्टिकोण पसंद है जो दूसरों ने उल्लेख किया है क्योंकि यह सवाल का जवाब देने लगता है (हालांकि आपको इसे मौजूदा ऐड()) से अलग विधि हस्ताक्षर देना होगा। साथ ही, ऐसा लगता है कि इस तरह की कॉल पर ऑब्जेक्ट रिटर्न के बारे में कुछ असंगतता है (मैंने सोचा था कि यह एक उत्परिवर्तन मुद्दा था, लेकिन स्ट्रिंगबिल्डर म्यूटेबल है ना?), तो आप एक दिलचस्प सवाल उठाते हैं।

मैं उत्सुक हूं, हालांकि, अगर AddRange विधि आउट-ऑफ-द-बॉक्स समाधान के रूप में काम नहीं करेगी? क्या कोई विशेष कारण है कि आप सरणी को एक सरणी के रूप में पास करने के बजाय कमांड को चेन करना चाहते हैं?

ऐसा कुछ ऐसा करने के लिए आपको क्या चाहिए?

List<string> list = new List<string>(); 
list.AddRange(new string[]{ 
    "first string", 
    "second string", 
}); 
1

आप एक अलग नाम के साथ एक विस्तार विधि का उपयोग कर सकते हैं:

public static T Put<T, U>(this T collection, U item) where T : ICollection<U> { 
    collection.Add(item); 
    return collection; 
} 

इस तरह कोड बनाने के लिए:

var list = new List<int>(); 
list.Put(1).Put(2).Put(3); 
नाम Add बनाए रखने के लिए

, हालांकि, आप एक हो सकता है इस तरह की विधि:

public static T Add<T, U>(this T collection, Func<U> itemProducer) 
    where T : ICollection<U> { 
    collection.Add(itemProducer()); 
    return collection; 
} 

और बनाने के कोड इस तरह:

list.Add(()=>1).Add(()=>2).Add(()=>3); 

हालांकि यह है कि अच्छी नहीं लगती है।

शायद अगर हम इस प्रकार को बदलते हैं तो हम बेहतर वाक्यविन्यास प्राप्त कर सकते हैं।

इस वर्ग को देखते हुए:

public class ListBuilder<T> { 
    IList<T> _list; 
    public ListBuilder(IList<T> list) { 
    _list = list; 
    } 
    public ListBuilder<T> Add(T item) { 
    _list.Add(item); 
    return this; 
    } 
} 

आप इस विधि का उपयोग कर सकते हैं:

public static ListBuilder<T> Edit<T>(this IList<T> list) { 
    return new ListBuilder<T>(list); 
} 

और इस तरह कोड का उपयोग करें:

list.Edit().Add(1).Add(2).Add(3); 
+1

बहुत अच्छा समाधान! –

1

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

लेखन lst.Add (obj) अपने कोड में मुक्त करने के लिए, lst संदर्भ एक सीपीयू रजिस्टर में उपलब्ध है।

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

+0

मुझे यकीन है कि आप इस टिप्पणी की सराहना नहीं करेंगे, लेकिन शायद आप समझा सकते हैं कि मैं उस उत्तर की सराहना क्यों नहीं करूंगा। यह अच्छी तरह लिखित, समझने में आसान था और अनुकूलन पर कुछ अच्छे अंक उठाए थे। –

संबंधित मुद्दे