2009-02-26 7 views
23

निम्नलिखित सामान्य वर्ग है कि या तो string, int, float, long प्रकार के रूप में होते हैं के बाद:सी #: विभिन्न प्रकार के साथ जेनेरिक कक्षाओं की एक सूची घोषित और उपयोग, कैसे?

public class MyData<T> 
{ 
    private T _data; 

    public MyData (T value) 
    { 
     _data = value; 
    } 

    public T Data { get { return _data; } } 
} 

मैं कहाँ प्रत्येक आइटम अलग T की होगी MyData<T> की एक सूची प्राप्त करने के लिए कोशिश कर रहा हूँ।

MyData<> myData = _myList[0]; // Could be <string>, <int>, ... 
SomeMethod (myData.Data); 

जहां SomeMethod() के रूप में घोषित किया जाता है इस प्रकार है::

public void SomeMethod (string value); 
public void SomeMethod (int value); 
public void SomeMethod (float value); 

मैं सूची से कोई आइटम का उपयोग करें और निम्न कोड में के रूप में अपने मूल्य प्राप्त करने में सक्षम होना चाहता हूँ

अद्यतन:

SomeMethod() एक और स्तरीय वर्ग से है जिसका मेरा नियंत्रण नहीं है और SomeMethod(object) मौजूद नहीं है।


हालांकि, मुझे कंपाइलर को खुश करने का कोई तरीका नहीं दिख रहा है।

कोई सुझाव?

धन्यवाद।

+0

आप अपने SomeMethod करता है पर विस्तृत सकता है? हम आपकी मदद करने में सक्षम हो सकते हैं। –

+0

क्या कुछ विधि करता है यहां प्रासंगिक नहीं है। मैं बस जोड़ दूंगा कि SomeMethod (ऑब्जेक्ट) के लिए कोई परिभाषा नहीं है। –

+0

आपका मूल डिजाइन त्रुटिपूर्ण है। मैं एक प्रश्न पूछने का सुझाव दूंगा जहां आप आवश्यकताओं और आपके समाधान की जानकारी देते हैं और सुझाव मांगते हैं। – Will

उत्तर

8

प्रतिनिधि वास्तव में इस आसान बनाने में मदद कर सकते हैं, और अभी भी बातें प्रकार सुरक्षित बनाए:

public void TestMethod1() 
{ 
    Action<SomeClass, int> intInvoke = (o, data) => o.SomeMethod(data); 
    Action<SomeClass, string> stringInvoke = (o, data) => o.SomeMethod(data); 

    var list = new List<MyData> 
    { 
     new MyData<int> { Data = 10, OnTypedInvoke = intInvoke }, 
     new MyData<string> { Data = "abc", OnTypedInvoke = stringInvoke } 
    }; 

    var someClass = new SomeClass(); 
    foreach (var item in list) 
    { 
     item.OnInvoke(someClass); 
    } 
} 

public abstract class MyData 
{ 
    public Action<SomeClass> OnInvoke; 
} 

public class MyData<T> : MyData 
{ 
    public T Data { get; set; } 
    public Action<SomeClass, T> OnTypedInvoke 
    { set { OnInvoke = (o) => { value(o, Data); }; } } 
} 

public class SomeClass 
{ 
    public void SomeMethod(string data) 
    { 
     Console.WriteLine("string: {0}", data); 
    } 

    public void SomeMethod(int data) 
    { 
     Console.WriteLine("int: {0}", data); 
    } 
} 
+0

उत्कृष्ट आंख खोलने वाला। – Telemat

0

गैर-जेनेरिक MyData कक्षा से इनरिट MyData<T> और इसकी एक सूची बनाएं।

इस तरह, आप अधिभार को स्वचालित रूप से हल नहीं कर सकते हैं। आपको इसे मैन्युअल रूप से करना है।

abstract class MyData { 
    protected abstract object GetData(); 
    protected abstract Type GetDataType(); 
    public object Data { 
     get { return GetData(); } 
    } 
    public Type DataType { 
     get { return GetDataType(); } 
    } 
} 

class MyData<T> : MyData { 
    protected override object GetData() { return Data; } 
    protected override Type GetDataType() { return typeof(T); } 
    public new T Data { 
    get { ... } 
    } 
} 
+0

ठीक है, अब मैं इसका उपयोग इस प्रकार करूंगा: सूची सूची = नई सूची (); सूची। जोड़ें (नया MyData ()); सूची। जोड़ें (नया MyData ()); कुछ विधि (सूची [0]। डेटा); किसी भी तरह, मुझे किसी वस्तु को स्वीकार करने की आवश्यकता होगी()। दुर्भाग्य से मुझे यह नहीं चाहिए। उत्तर देने के लिए धन्यवाद। स्टीसी –

+0

हां, यही कारण है कि मैंने कहा कि आपको प्रकार पर विचार करके मैन्युअल रूप से ओवरलोड प्रबंधित करना चाहिए। जेनेरिक द्वारा समर्थित प्रत्यक्ष तरीका नहीं है। –

1

उस मामले में आप MyData<object> की जरूरत के बाद से है कि केवल एक चीज उन प्रकार के आम में है है।

+2

MyData कैसे कुछ Method (int) को कॉल करने की अनुमति देता है? –

0

जेनेरिक्स जब आप सूची बनाते हैं, उदाहरण के लिए पूर्णांक के भंडारण के लिए एक सूची इस

var myData = new MyData<int>(); 

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

var myData = new MyData<object>(); 

लेकिन आप वस्तुओं को संग्रहीत करने के लिए गैर-जेनेरिक सूची का उपयोग कर सकते हैं।

6

बस एक ऐरेलिस्ट का उपयोग करें और MyData<T> प्रकार को भूलें।

ArrayList myStuff = getStuff(); 
float x = myStuff.OfType<float>().First(); 
SomeMethod(x); 
string s = myStuff.OfType<string>().First(); 
SomeMethod(s); 

MyData<T> के साथ समस्या यह है कि आप एक प्रकार है कि केवल कार्यावधि में जाना जाता है की जाँच करने के संकलक की उम्मीद कर रहे है। कंपाइलर चेक प्रकार जो संकलन समय पर ज्ञात हैं।

+0

धन्यवाद! यह मेरी व्यक्तिगत समस्या का जवाब था। ब्लॉकिंग कोलेक्शन की एक सूची का ट्रैक रखने की कोशिश कर रहा था, और फिर GetQueue के माध्यम से जांचें जहां टी: इंटरफ़ेस विधि मेरी सूची में पहले से मौजूद प्रकार टी की कतार है या नहीं, और यदि नहीं, तो नई खाली कतार को तुरंत चालू करें और वापस कर दें। लेकिन ब्लॉकिंग कोलेक्शन को अवरुद्ध रूप से ब्लॉकिंग कोलेक्शन में नहीं डाला जा सकता है, यहां तक ​​कि टी: इंटरफ़ेस भी सोचा जा सकता है, और मैं इस – Isaac

3

आप इसे जिस तरह से चाहते हैं उसे नहीं कर सकते हैं।

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

हालांकि, इसका मतलब है कि डेटा प्रॉपर्टी अब ऑब्जेक्ट के ऑब्जेक्ट को वापस कर देगी। संकलक संकलन समय पर वास्तविक डेटा प्रकार का अनुमान नहीं लगा सकता है, इसलिए यह उपयुक्त SomeMethod अधिभार चुन सकता है।

आपको या तो SomeMethod का अधिभार प्रदान करना होगा जो ऑब्जेक्ट को पैरामीटर के रूप में लेता है, या आपके संग्रह में ऐसे विभिन्न प्रकारों को रखने के लिए आवश्यकता को हटा देता है।

या आप मानक IEnumerable संग्रह (ऐरे की तरह) के साथ जा सकते हैं और OfType<> एक्सटेंशन विधि का उपयोग विशेष प्रकार के संग्रह के सबसेट प्राप्त करने के लिए कर सकते हैं।

+0

को करने के लिए सही कॉन्वेंट/contravariant/प्रतिनिधि कार्यान्वयन खोजने के लिए नहीं कर सकता था, मुझे डर था कि यह किसी ऑब्जेक्ट का उपयोग करने का संकल्प करेगा। .. हालांकि, मैं किसी ऑब्जेक्ट का उपयोग नहीं कर सकता क्योंकि SomeMethod लाइब्रेरी से है और मैं इस तथ्य को नहीं बदल सकता कि यह किसी ऑब्जेक्ट को स्वीकार नहीं करेगा ... इसके अलावा, मैं स्विच नहीं करना चाहता () चर के प्रकार पर ... –

1

कुछ समय पहले वाइल्डकार्ड सुझाए गए here। "ठीक नहीं होगा" के रूप में बंद :(

13

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

public class MyData<T, C> 
    where T : IData<C> 
{ 
    public T Data { get; private set; } 

    public MyData (T value) 
    { 
     Data = value; 
    } 
} 

public interface IData<T> 
{ 
    T Data { get; set; } 
    void SomeMethod(); 
} 

//you'll need one of these for each data type you wish to support 
public class MyString: IData<string> 
{ 
    public MyString(String value) 
    { 
     Data = value; 
    } 

    public void SomeMethod() 
    { 
     //code here that uses _data... 
     Console.WriteLine(Data); 
    } 

    public string Data { get; set; } 
} 

और फिर आप कार्यान्वयन किया जाएगा हों तो वहां की तरह:

var myData = new MyData<MyString, string>(new MyString("new string"));  
// Could be MyString, MyInt, ... 
myData.Data.SomeMethod(); 

यह थोड़ा और काम है लेकिन आपको वह कार्यक्षमता मिलती है जिसके लिए आप जा रहे थे।

अद्यतन: अपने इंटरफेस से निकालें SomeMethod और बस करना यह

SomeMethod(myData.Data.Data); 
+0

बहुत बुरा मुझे आदिम प्रकारों को लपेटने की ज़रूरत है, लेकिन ऐसा कुछ है जिसे मैं स्वीकार करने के लिए तैयार हूं क्योंकि ऐसा कोई अन्य तरीका नहीं है। हालांकि, आपके उदाहरण में, आपने माना है कि SomeMethod() MyData का हिस्सा था जो मामला नहीं है (मैंने प्रश्न अपडेट किया है)। –

+0

असल में आप एक ही चीज़ को पूरा कर सकते हैं, मैंने इसे अभी लपेट लिया है, इसलिए यह अधिक encapsulated होगा, मेरे अपडेट – Joseph

+0

देखें तो ... एक कैसे एक ही संग्रह में MyData और MyData को स्थानांतरित करता है? IDataType, और उसके बाद हर ठोस प्रकार IDataType को लागू करने के साथ ही होता है, का कहना है कि वर्ग MyString: –

1

आप SomeMethod के लिए एक सामान्य आवरण बना सकते हैं और सामान्य तर्क के प्रकार के लिए जाँच कर सकते हैं, तो उपयुक्त विधि प्रतिनिधि।

public void SomeMethod<T>(T value) 
{ 
    Type type = typeof(T); 

    if (type == typeof(int)) 
    { 
     SomeMethod((int) (object) value); // sadly we must box it... 
    } 
    else if (type == typeof(float)) 
    { 
     SomeMethod((float) (object) value); 
    } 
    else if (type == typeof(string)) 
    { 
     SomeMethod((string) (object) value); 
    } 
    else 
    { 
     throw new NotSupportedException(
      "SomeMethod is not supported for objects of type " + type); 
    } 
} 
+0

आपके उत्तर के लिए धन्यवाद। मुझे डर है कि मुझे मुक्केबाजी/अनबॉक्सिंग का उपयोग करना होगा। मैंने सोचा कि एक और अधिक कुशल तरीका होना चाहिए .. –