सी # जेनरिक में शून्य?


94

मेरे पास एक सामान्य तरीका है जो एक अनुरोध लेता है और एक प्रतिक्रिया प्रदान करता है।

public Tres DoSomething<Tres, Treq>(Tres response, Treq request)
{/*stuff*/}

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

public Tre DoSomething<Tres>(Tres response)
{
    return DoSomething<Tres, void>(response, null);
}

क्या यह किसी तरह से संभव है? ऐसा लगता है कि विशेष रूप से शून्य का उपयोग करना काम नहीं करता है, लेकिन मैं कुछ अनुरूप खोजने की उम्मीद कर रहा हूं।


1
सिर्फ़ System.Object का उपयोग क्यों न करें और DoSomething में एक शून्य जांच करें (ट्रेस प्रतिक्रिया, ट्रेक अनुरोध)?
जेम्स

ध्यान दें कि आपको वापसी मूल्य का उपयोग करने की आवश्यकता है। आप प्रक्रियाओं जैसे कार्यों को कॉल कर सकते हैं। DoSomething(x);इसके बजायy = DoSomething(x);
ओलिवियर जैकोट-डेसकॉम्ब्स

1
मुझे लगता है कि आपका कहने का मतलब है, "ध्यान दें कि आपको रिटर्न वैल्यू का उपयोग करने की आवश्यकता नहीं है।" @ ओलिवियरजैकॉट-डेस्कोम्स
ज़ानडेप

जवाबों:


95

आप उपयोग नहीं कर सकते void, लेकिन आप उपयोग कर सकते हैं object: यह थोड़ी असुविधा है क्योंकि आपके होने वाले voidकार्यों को वापस करने की आवश्यकता होती है null, लेकिन यदि यह आपके कोड को एकीकृत करता है, तो इसका भुगतान करने के लिए एक छोटी सी कीमत होनी चाहिए।

voidरिटर्न प्रकार के रूप में उपयोग करने की यह अक्षमता सामान्य प्रतिनिधियों के परिवारों Func<...>और Action<...>परिवारों के बीच विभाजन के लिए कम से कम आंशिक रूप से जिम्मेदार है : यह वापसी करना संभव था void, सभी Action<X,Y,Z>बस बन जाएंगे Func<X,Y,Z,void>। दुर्भाग्य से, यह संभव नहीं है।


45
(मजाक) और वह अभी भी voidउन-से-शून्य तरीकों से वापस आ सकता है, के साथ return System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(void));। यह एक बॉक्सिंग शून्य होगा, हालांकि।
जेपी स्टिग नीलसन

जैसा कि C # अधिक कार्यात्मक प्रोग्रामिंग सुविधाओं का समर्थन करता है, आप एफपी में प्रतिनिधित्व करने वाली इकाई पर एक नज़र डाल सकते हैं void। और इसका उपयोग करने के अच्छे कारण हैं। F #, अभी भी .NET में, हमने unitअंतर्निहित है।
जो

88

नहीं दुर्भाग्य से नहीं। यदि voidएक "वास्तविक" प्रकार (जैसे unitएफ # में , उदाहरण के लिए) जीवन कई मायनों में बहुत सरल होगा। विशेष रूप से, हम दोनों की जरूरत नहीं होगी Func<T>और Action<T>परिवारों - वहाँ सिर्फ होगी Func<void>बजाय Action, Func<T, void>के बजाय Action<T>आदि

यह भी async को सरल बना देगा - गैर-सामान्य Taskप्रकार की कोई आवश्यकता नहीं होगी - हमारे पास बस होगा Task<void>

दुर्भाग्य से, यह C # या .NET टाइप सिस्टम के काम करने का तरीका नहीं है ...


4
Unfortunately, that's not the way the C# or .NET type systems work...तुम मुझे उम्मीद कर रहे थे कि शायद चीजें उस तरह से काम कर सकती हैं। क्या आपके अंतिम बिंदु का मतलब है कि हम कभी भी इस तरह से काम करने की संभावना नहीं रखते हैं?
डेव कज़िन्यू

2
@Sahuagin: मुझे संदेह नहीं है - यह इस बिंदु पर एक बहुत बड़ा बदलाव होगा।
जॉन स्कीट

1
@stannius: नहीं, यह एक ऐसी असुविधा से कहीं अधिक है जो गलत कोड की ओर ले जाती है, मुझे लगता है।
जॉन स्कीट

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

1
@Ondrej: मैंने पहले चीजों के लिए एक खाली संरचना का उपयोग करने की कोशिश की है, और यह समाप्त होता है CLR में खाली नहीं होना चाहिए ... यह विशेष-आवरण हो सकता है, निश्चित रूप से। इसके अलावा, मुझे नहीं पता कि मैं क्या सुझाव दूंगा; मैंने इसके बारे में ज्यादा नहीं सोचा है।
जॉन स्कीट

27

यहाँ आप क्या कर सकते हैं। जैसा @JohnSkeet ने कहा कि C # में कोई इकाई प्रकार नहीं है, इसलिए इसे स्वयं बनाएं!

public sealed class ThankYou {
   private ThankYou() { }
   private readonly static ThankYou bye = new ThankYou();
   public static ThankYou Bye { get { return bye; } }
}

अब आप हमेशा के Func<..., ThankYou>बजाय उपयोग कर सकते हैंAction<...>

public ThankYou MethodWithNoResult() {
   /* do things */
   return ThankYou.Bye;
}

या Rx टीम द्वारा पहले से बनाई गई किसी चीज़ का उपयोग करें: http://msdn.microsoft.com/en-us/library/system.reactive.unit%28v=VS.103%29.aspx


System.Reactive.Unit एक अच्छा सुझाव है। नवंबर 2016 तक, यदि आप संभव के रूप में प्रतिक्रियाशील ढांचे के एक छोटे टुकड़े को प्राप्त करने में रुचि रखते हैं, क्योंकि आप यूनिट वर्ग के अलावा किसी अन्य चीज का उपयोग नहीं कर रहे हैं, तो नगेट पैकेज मैनेजर का उपयोग करेंInstall-Package System.Reactive.Core
DannyMeister

6
"KThx" का नाम बदलें, और यह एक विजेता है। ^ _ ^Kthx.Bye;
LexH

बस यह जांचने के लिए कि मैं कुछ याद नहीं कर रहा हूँ .. अलविदा गटर सीधे यहाँ तक पहुँचने पर कुछ भी नहीं जोड़ता है?
एंड्रयू

1
@ और जब तक आप सी # कोडिंग की भावना का पालन नहीं करना चाहते हैं, तब तक आपको अलविदा कहने की ज़रूरत नहीं है, जो कहता है कि आपको नंगे खेतों को उजागर नहीं करना चाहिए
ट्रिडेंट

16

आप Objectदूसरों के सुझाव के अनुसार उपयोग कर सकते हैं । या Int32जो मैंने कुछ उपयोग देखा है। उपयोग Int32करने से एक "डमी" संख्या (उपयोग 0) का परिचय होता है , लेकिन कम से कम आप किसी भी बड़ी और विदेशी वस्तु को Int32संदर्भ में नहीं रख सकते (संरचनाएं सील हो जाती हैं)।

आप भी लिख सकते हैं "शून्य" प्रकार:

public sealed class MyVoid
{
  MyVoid()
  {
    throw new InvalidOperationException("Don't instantiate MyVoid.");
  }
}

MyVoidसंदर्भों की अनुमति है (यह एक स्थिर वर्ग नहीं है) लेकिन केवल हो सकता है null। उदाहरण निर्माता निजी है (और यदि कोई प्रतिबिंब के माध्यम से इस निजी निर्माता को कॉल करने की कोशिश करता है, तो एक अपवाद उन पर फेंक दिया जाएगा)।


चूँकि वैल्यू ट्यूपल्स (2017, .NET 4.7) पेश किए गए थे, इसलिए इस तरह के बजाय संरचनाValueTuple (0-ट्यूपल, गैर-जेनेरिक संस्करण) का उपयोग करना स्वाभाविक है MyVoid। इसके उदाहरण में एक ToString()रिटर्न है "()", इसलिए यह शून्य-ट्यूपल की तरह दिखता है। C # के वर्तमान संस्करण के रूप में, आप ()एक उदाहरण प्राप्त करने के लिए कोड में टोकन का उपयोग नहीं कर सकते । आप इसके बजाय ( default(ValueTuple)या defaultजब संदर्भ से प्रकार का अनुमान लगाया जा सकता है) का उपयोग कर सकते हैं।


2
इसका एक अन्य नाम नल ऑब्जेक्ट पैटर्न (डिजाइन पैटर्न) होगा।
अनलफिस

@Aelphaeis यह अवधारणा एक अशक्त वस्तु पैटर्न से थोड़ी अलग है। यहाँ, बिंदु कुछ प्रकार का है जिसे हम जेनेरिक के साथ उपयोग कर सकते हैं। एक अशक्त वस्तु पैटर्न के साथ लक्ष्य एक ऐसी विधि लिखने से बचना है जो एक विशेष मामले को इंगित करने के लिए अशक्त हो जाता है और इसके बजाय वास्तविक डिफ़ॉल्ट व्यवहार के साथ एक वास्तविक वस्तु लौटाता है।
एंड्रयू पामर

8

मुझे ऊपर से एलेक्सी बायकोव का विचार पसंद है, लेकिन इसे थोड़ा सरल किया जा सकता है

public sealed class Nothing {
    public static Nothing AtAll { get { return null; } }
}

जैसा कि मैंने कोई स्पष्ट कारण नहीं देखा कि कुछ भी क्यों नहीं। कोई भी बस अशक्त नहीं दे सकता है

एक ही विचार (या जेपी स्टिग नीलसन द्वारा एक) टाइप किए गए वर्गों के साथ उपयोग के लिए भी महान है।

उदाहरण के लिए, यदि किसी प्रक्रिया / फ़ंक्शन के तर्कों का वर्णन करने के लिए केवल टाइप का उपयोग किसी विधि के तर्क के रूप में किया जाता है, और यह स्वयं कोई तर्क नहीं लेता है।

(आपको अभी भी डमी आवरण बनाने या वैकल्पिक "नथिंग" की अनुमति देने की आवश्यकता होगी। लेकिन IMHO वर्ग का उपयोग myClass के साथ अच्छा लग रहा है <Nothing>)

void myProcWithNoArguments(Nothing Dummy){
     myProcWithNoArguments(){
}

या

void myProcWithNoArguments(Nothing Dummy=null){
    ...
}

1
मूल्य nullमें एक लापता या अनुपस्थित होने का अर्थ है object। एक Nothingसाधन के लिए सिर्फ एक मूल्य होने से यह कभी और कुछ नहीं दिखता है।
२२:२५ बजे लेक्सएच

यह एक अच्छा विचार है, लेकिन मैं @LexieHankins से सहमत हूं। मुझे लगता है कि "कुछ भी नहीं" के लिए बेहतर होगा कि Nothingएक निजी स्थिर क्षेत्र में संग्रहीत वर्ग का एक अनूठा उदाहरण हो और एक निजी कंस्ट्रक्टर को जोड़ा जाए। तथ्य यह है कि अशक्त अभी भी संभव है कष्टप्रद है, लेकिन वह हल हो जाएगा, उम्मीद है कि सी # 8 के साथ
Kirk Woll

अकादमिक रूप से मैं भेद को समझता हूं, लेकिन यह एक विशेष मामला होगा जहां अंतर मायने रखता है। (सामान्य अशक्त प्रकार के एक फ़ंक्शन की कल्पना करें, जहां "नल" की वापसी का उपयोग एक विशेष मार्कर के रूप में किया जाता है, जैसे कि किसी प्रकार की त्रुटि मार्कर के रूप में)
Eske Rahn

4

voidहालांकि, एक प्रकार, केवल एक विधि के रिटर्न प्रकार के रूप में मान्य है।

इस सीमा के आसपास कोई रास्ता नहीं है void


1

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

public sealed class Void {
    private Void() { }
}

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