2010-03-04 6 views
6

मान लीजिए मैं निम्नलिखित के साथ एक पुस्तकालय लिखें:क्या किसी अन्य प्रकार से परिवर्तनीय होने के लिए एक प्रकार पैरामीटर के लिए एक सामान्य बाधा निर्दिष्ट करना संभव है?

public class Bar { /* ... */ } 

public class SomeWeirdClass<T> 
    where T : ??? 
{ 
    public T BarMaker(Bar b) 
    { 
     // ... play with b 
     T t = (T)b 
     return (T) b; 
    } 
} 

बाद में, मैं उपयोगकर्ताओं को अपने स्वयं प्रकार जो बार के लिए परिवर्तनीय हैं परिभाषित करने और SomeWeirdClass 'कारखाना' का उपयोग करके अपनी लाइब्रेरी का उपयोग करने की उम्मीद है।

public class Foo 
{ 
    public static explicit operator Foo(Bar f) 
    { 
     return new Bar(); 
    } 
} 

public class Demo 
{ 
    public static void demo() 
    { 
     Bar b = new Bar(); 
     SomeWeirdClass<Foo> weird = new SomeWeirdClass<Foo>(); 
     Foo f = weird.BarMaker(b); 
    } 
} 

अगर मैं where T : Foo निर्धारित करते हैं लेकिन समस्या यह है कि मैं लाइब्रेरी की संकलन समय पर फू के बारे में पता नहीं है, और मैं वास्तव में चाहते हैं और अधिक where T : some class that can be instantiated, given a Bar

की तरह कुछ इस संभव है है इस संकलन होगा? मेरे सीमित ज्ञान से ऐसा प्रतीत नहीं होता है, लेकिन .NET ढांचे और उसके उपयोगकर्ताओं की सरलता मुझे आश्चर्यचकित करती है ...

यह static interface methods के विचार से संबंधित हो सकता है या नहीं - कम से कम, मैं देख सकता हूं कारखाने के तरीकों की उपस्थिति वस्तुओं

संपादित (एक ही तरीका है कि आप पहले से ही प्रदर्शन कर सकते हैं where T : new() के समान) बनाने के लिए निर्दिष्ट करने के लिए सक्षम किया जा रहा में मूल्य: - निक और bzIm करने के लिए धन्यवाद - समाधान अन्य पाठकों के लिए मैं हूँ एक पूर्ण समाधान प्रदान करें क्योंकि मैं इसे समझता हूं: संपादन 2: इस समाधान के लिए सार्वजनिक डिफ़ॉल्ट कन्स्ट्रक्टर का पर्दाफाश करने के लिए Foo की आवश्यकता है। यहां तक ​​कि स्टूपर बेहतर समाधान के लिए इस पोस्ट के बहुत नीचे देखने की आवश्यकता नहीं है।

public class Bar {} 

public class SomeWeirdClass<T> 
    where T : IConvertibleFromBar<T>, new() 
{ 
    public T BarMaker(Bar b) 
    { 
     T t = new T(); 
     t.Convert(b); 
     return t; 
    } 
} 

public interface IConvertibleFromBar<T> 
{ 
    T Convert(Bar b); 
} 

public class Foo : IConvertibleFromBar<Foo> 
{ 
    public static explicit operator Foo(Bar f) 
    { 
     return null; 
    } 

    public Foo Convert(Bar b) 
    { 
     return (Foo) b; 
    } 
} 

public class Demo 
{ 
    public static void demo() 
    { 
     Bar b = new Bar(); 
     SomeWeirdClass<Foo> weird = new SomeWeirdClass<Foo>(); 
     Foo f = weird.BarMaker(b); 
    } 
} 

EDIT2: समाधान 2: एक प्रकार कनवर्टर कारखाना बनाएं उपयोग करने के लिए:

#region library defined code 

public class Bar {} 

public class SomeWeirdClass<T, TFactory> 
    where TFactory : IConvertorFactory<Bar, T>, new() 
{ 
    private static TFactory convertor = new TFactory(); 

    public T BarMaker(Bar b) 
    { 
     return convertor.Convert(b); 
    } 
} 

public interface IConvertorFactory<TFrom, TTo> 
{ 
    TTo Convert(TFrom from); 
} 

#endregion 

#region user defined code 

public class BarToFooConvertor : IConvertorFactory<Bar, Foo> 
{ 
    public Foo Convert(Bar from) 
    { 
     return (Foo) from; 
    } 
} 

public class Foo 
{ 
    public Foo(int a) {} 

    public static explicit operator Foo(Bar f) 
    { 
     return null; 
    } 

    public Foo Convert(Bar b) 
    { 
     return (Foo) b; 
    } 
} 

#endregion 

public class Demo 
{ 
    public static void demo() 
    { 
     Bar b = new Bar(); 
     SomeWeirdClass<Foo, BarToFooConvertor> weird = new SomeWeirdClass<Foo, BarToFooConvertor>(); 
     Foo f = weird.BarMaker(b); 
    } 
} 
+3

उन्हें बनाने के लिए * आसान * बनाने के लिए एपीआई बनाने का मुद्दा नहीं है? –

+1

इसे एक दिलचस्प शैक्षणिक प्रश्न पर विचार करें। – fostandy

उत्तर

4

मुझे नहीं लगता कि वहाँ जरूरी इस भाषा में निर्मित करने के लिए एक वाक्य रचना अच्छा तरीका है।

public interface IConvertible<T> 
    where T : new() // Probably will need this 
{ 
    T Convert(); 
} 

फिर अपने वर्ग हो सकता है: आपकी समस्या का एक संभव समाधान एक परिवर्तनीय इंटरफेस को परिभाषित करने से हो सकता है

public class Foo : IConvertible<Bar> 
{ 
} 

मैं इस आप जहाँ आप होना चाहते करने के लिए बंद हो जाता है लगता है ... सभी आपके प्रश्न में फू और बार कभी-कभी यह निर्धारित करना मुश्किल बनाते हैं कि आपका इरादा क्या है। उम्मीद है की यह मदद करेगा।

संपादित करें: जहां जोड़ा गया बाधा ... आप शायद अपने परिवर्तनीय वर्ग में एक नया उदाहरण बनाने में सक्षम होना होगा।

संपादित करें 2: मेड फू वारिस ICovertible<Bar>

+0

मेरी समझ तब है जब मैं एक फू परिभाषित करता हूं: IConvertible ? इससे मुझे बार उदाहरणों में फू इंस्टेंस को कन्वर्ट करने की अनुमति मिल जाएगी, लेकिन मैं वास्तव में बार उदाहरणों को फू इंस्टेंस में कनवर्ट करना चाहता हूं। मुझे लगता है कि मुझे वास्तव में बार को लागू करने की आवश्यकता होगी: IConvertible - लेकिन निश्चित रूप से लाइब्रेरी-संकलन-समय पर Foo को नहीं जानते, मैं यह नहीं कर सकता। – fostandy

+0

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

+0

@fostandy - ईमानदार होने के लिए, मुझे यह समझने में कठिनाई हो रही है कि आप क्या करने की कोशिश कर रहे हैं, खासकर फूओस, बार्स के साथ, और कह रहे हैं कि आप लाइब्रेरी संकलन समय पर Foo नहीं जानते हैं? क्या आप अपने प्रश्न को थोड़ा-सा खराब कर सकते हैं? – Nick

1

से आप एक इंटरफेस है जो एक प्रकार बाधा के रूप में प्रयोग किया जाता है के माध्यम से एक चक्कर बना सकता है।

उदाहरण के लिए, where T : IComparable<U> किसी अन्य चीज़ की तुलना में किसी प्रकार की चीज़ को बाधित करने के लिए उपयोग किया जाता है, जिसे IComparable<another> लागू करके इस क्षमता को व्यक्त करना होगा। यदि आपके पास ICastableFrom<T> इंटरफ़ेस था, तो आप उन्हें ICastableFrom<Bar> लागू करने के लिए मजबूर कर सकते हैं।

4

लगता है जैसे आपको बड़ी समस्या का समाधान मिला।अपने विशिष्ट प्रश्न का उत्तर देने के लिए: नहीं, न तो सी # और न ही सीएलआर "पिछड़ा" सामान्य प्रकार पैरामीटर बाधा का समर्थन करता है। यही कारण है,

class C<T> where Foo : T 

समर्थित नहीं है "टी फू या एक प्रकार है जो फू धर्मान्तरित करने के लिए होना चाहिए"।

ऐसी भाषाएं हैं जिनमें इस प्रकार की बाधा है; आईआईआरसी स्कैला ऐसी भाषा है। मुझे संदेह है कि यह सुविधा contravariant इंटरफेस के कुछ उपयोगों के लिए आसान होगा।

1

बजाय एक इंटरफेस को परिभाषित करने और है कि इंटरफ़ेस को लागू करने के लिए अपने वर्ग को संशोधित करने की मुसीबत के माध्यम से जाना है, यही कारण है कि अभी ऐसा नहीं?

public class SomeWeirdClass<T> 
{ 
    // aside: why is this method called 'BarMaker' if it returns a T? 
    public T BarMaker(Bar b, Func<Bar, T> converter) 
    { 
     // ... play with b 
     return converter(b); 
    } 
} 

तब घटना है कि आप एक प्रकार T को जो Bar सीधे डाली जा सकती है, का एक उद्देश्य के साथ काम कर रहे हैं, इस विधि के रूप में बस कहा जा सकता है इस प्रकार है:

var someWeirdObject = new SomeWeirdClass<Foo>(); 
var someBar = new Bar(); 
var someFoo = someWeirdObjcet.BarMaker(someBar, bar => bar as Foo); 

वैसे (चूंकि Func<T, TResult> प्रतिनिधि .NET 3.5 में उभरा है), आप converter पैरामीटर के लिए Converter<TInput, TOutput> (जो बिल्कुल वही है) का उपयोग कर सकते हैं।

+0

उत्कृष्ट बिंदु। मुझे लगता है कि मुझे जेनेरिक और बाधाओं पर इतना फिक्स किया गया है, मैंने इसे पूरी तरह से याद किया। – fostandy

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

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