C # या .NET में देखे गए सबसे अजीब कोने का मामला क्या है? [बन्द है]


322

मैं कुछ कोने के मामलों और मस्तिष्क के टीज़र एकत्र करता हूं और हमेशा अधिक सुनना चाहता हूं । पृष्ठ केवल वास्तव में C # भाषा बिट्स और बोब्स को कवर करता है, लेकिन मुझे कोर .NET चीजें भी दिलचस्प लगती हैं। उदाहरण के लिए, यहाँ एक है जो पृष्ठ पर नहीं है, लेकिन जो मुझे अविश्वसनीय लगता है:

string x = new string(new char[0]);
string y = new string(new char[0]);
Console.WriteLine(object.ReferenceEquals(x, y));

मैं उम्मीद करूंगा कि फाल्स को प्रिंट करने के लिए - आखिरकार, "नया" (एक संदर्भ प्रकार के साथ) हमेशा एक नई वस्तु बनाता है, है ना? C # और CLI दोनों के लिए चश्मा इंगित करता है कि यह होना चाहिए। खैर, इस विशेष मामले में नहीं। यह सच को प्रिंट करता है, और मैंने जिस फ्रेमवर्क के साथ इसका परीक्षण किया है, उसके हर संस्करण पर किया है। (मैंने मोनो पर कोशिश नहीं की है, स्वीकार किया है ...)

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

किसी अन्य रत्न वहाँ बाहर दुबकना?


64
मोनो 2.0 आरसी पर परीक्षण किया गया; यह सच है देता है
मार्क Gravell

10
दोनों तार कड़े होते जा रहे हैं। खाली है और ऐसा प्रतीत होता है कि फ्रेमवर्क केवल एक ही संदर्भ रखता है
एड्रियन ज़ानस्कु

34
यह स्मृति संरक्षण की बात है। स्थिर विधि string.Intern के लिए MSDN प्रलेखन देखें। CLR एक स्ट्रिंग पूल रखता है। यही कारण है कि समान सामग्री के साथ तार एक ही मेमोरी यानी ऑब्जेक्ट के संदर्भ के रूप में दिखाई देते हैं।
जॉन लेदरग्रेन

12
@ जॉन: स्ट्रिंग इंटर्निंग केवल शाब्दिक रूप से होती है । यहाँ ऐसा नहीं है। @DanielSwe: स्ट्रिंग्स को अपरिवर्तनीय बनाने के लिए इंटरस्टिंग की आवश्यकता नहीं है । तथ्य यह है कि यह संभव है अपरिवर्तनीयता का एक अच्छा कोरोलरी है, लेकिन सामान्य इंटर्निंग वैसे भी यहां नहीं हो रहा है।
जॉन स्कीट

3
: कार्यान्वयन विस्तार है कि इस व्यवहार का कारण बनता है यहाँ से समझाया गया है blog.liranchen.com/2010/08/brain-teasing-with-strings.html
Liran

जवाबों:


394

मुझे लगता है कि मैंने आपको यह पहले दिखाया था, लेकिन मुझे यहाँ मज़ा पसंद है - यह नीचे ट्रैक करने के लिए कुछ डिबगिंग ले गया! (मूल कोड स्पष्ट रूप से अधिक जटिल और सूक्ष्म था ...)

    static void Foo<T>() where T : new()
    {
        T t = new T();
        Console.WriteLine(t.ToString()); // works fine
        Console.WriteLine(t.GetHashCode()); // works fine
        Console.WriteLine(t.Equals(t)); // works fine

        // so it looks like an object and smells like an object...

        // but this throws a NullReferenceException...
        Console.WriteLine(t.GetType());
    }

तो क्या था टी ...

उत्तर: कोई भी Nullable<T>- जैसे int?। GetType () जो नहीं हो सकता, को छोड़कर सभी विधियां ओवरराइड की गई हैं; इसलिए इसे ऑब्जेक्ट (और इसलिए शून्य करने के लिए) (कॉल करने के लिए) ऑब्जेक्ट को कॉल किया जाता है। गेट टाइप () ... जो null पर कॉल करता है; -पी


अपडेट: कथानक मोटा होता है ... आयेंद रहियन ने अपने ब्लॉग पर इसी तरह की चुनौती दी , लेकिन साथ where T : class, new():

private static void Main() {
    CanThisHappen<MyFunnyType>();
}

public static void CanThisHappen<T>() where T : class, new() {
    var instance = new T(); // new() on a ref-type; should be non-null, then
    Debug.Assert(instance != null, "How did we break the CLR?");
}

लेकिन इसे हराया जा सकता है! रेमोटिंग जैसी चीजों द्वारा उपयोग किए जाने वाले उसी अप्रत्यक्ष का उपयोग करना; चेतावनी - निम्नलिखित शुद्ध बुराई है :

class MyFunnyProxyAttribute : ProxyAttribute {
    public override MarshalByRefObject CreateInstance(Type serverType) {
        return null;
    }
}
[MyFunnyProxy]
class MyFunnyType : ContextBoundObject { }

इसके स्थान पर, new()कॉल को प्रॉक्सी ( MyFunnyProxyAttribute) पर पुनर्निर्देशित किया जाता है , जो वापस लौटता है null। अब जाओ और अपनी आँखें धो लो!


9
Nullable <T> .GetType () को परिभाषित क्यों नहीं किया जा सकता है? क्या परिणाम टाइपो (अशक्त <टी>) नहीं होना चाहिए?
ड्रू नोक

69
आकर्षित: समस्या यह है कि GetType () आभासी नहीं है, इसलिए इसे ओवरराइड नहीं किया जाता है - जिसका अर्थ है कि विधि कॉल के लिए मूल्य बॉक्सिंग है। बॉक्स एक शून्य संदर्भ बन जाता है, इसलिए एनआरई।
जॉन स्कीट

10
@Drew; इसके अलावा, Nullable <T> के लिए विशेष बॉक्सिंग नियम हैं, जिसका अर्थ है कि रिक्त Nullable <T> बॉक्स रिक्त करने के लिए, न कि एक खाली Nullable <T> (और एक अशक्त अशक्त बॉक्स से रिक्त Nullable <T)। >)
मार्क Gravell

29
बहुत बहुत शांत। एक अनचाही तरह से। ;-)
कोनराड रूडोल्फ

6
निर्माता-बाधा, सी # 3.0 भाषा के कल्पना में 10.1.5
मार्क Gravell

216

बैंकरों की गोलाई।

यह एक संकलक बग या खराबी नहीं है, लेकिन निश्चित रूप से एक अजीब कोने का मामला है ...

.Net फ्रेमवर्क एक स्कीम या राउंडिंग को नियुक्त करता है जिसे बैंकर के राउंडिंग के रूप में जाना जाता है।

बैंकरों में ०.५ संख्याओं को गोल करके निकटतम सम संख्या में गोल किया जाता है, इसलिए

Math.Round(-0.5) == 0
Math.Round(0.5) == 0
Math.Round(1.5) == 2
Math.Round(2.5) == 2
etc...

यह अधिक प्रसिद्ध राउंड-हाफ-अप राउंडिंग के आधार पर वित्तीय गणना में कुछ अप्रत्याशित बग पैदा कर सकता है।

यह Visual Basic का भी सच है।


22
यह मुझे भी अजीब लग रहा था। यही है, कम से कम, जब तक मैंने संख्याओं की एक बड़ी सूची को गोल नहीं किया और उनकी राशि की गणना नहीं की। तब आपको पता चलता है कि यदि आप बस गोल करते हैं, तो आप गैर-गोल संख्याओं के योग से संभावित भारी अंतर को समाप्त कर देंगे। बहुत बुरा है अगर आप वित्तीय गणना कर रहे हैं!
Tsvetomir Tsonev

255
मामले में लोगों को पता नहीं था, आप कर सकते हैं: Math.Round (x, MidpointRounding.AwayFromZero); गोलाई योजना को बदलना।
आईसीआर

26
डॉक्स से: इस विधि का व्यवहार IEEE Standard 754, खंड 4 का अनुसरण करता है। इस तरह की गोलाई को कभी-कभी निकटतम, या बैंकर की गोलाई कहा जाता है। यह एक एकल दिशा में एक मिडपॉइंट मान को लगातार गोल करने से उत्पन्न होने वाली गोलाई त्रुटियों को कम करता है।
ICR

8
मुझे आश्चर्य है कि यही वजह है कि मैं int(fVal + 0.5)इतनी बार उन भाषाओं में भी देखता हूं जिनमें एक अंतर्निहित राउंडिंग फ़ंक्शन होता है।
बेन ब्लैंक

32
विडंबना यह है कि मैंने एक बार एक बैंक में काम किया था और अन्य प्रोग्रामर ने इस बारे में सोचना शुरू कर दिया था, यह सोचते हुए कि फ्रेमिंग में गोलाई टूट गई थी
dan

176

यदि इस फ़ंक्शन Rec(0)को डिबगर के तहत नहीं कहा जाता है, तो यह क्या करेगा ?

static void Rec(int i)
{
    Console.WriteLine(i);
    if (i < int.MaxValue)
    {
        Rec(i + 1);
    }
}

उत्तर:

  • 32-बिट JIT पर यह एक StackOverflowException में परिणाम होना चाहिए
  • 64-बिट JIT पर इसे int.MaxValue के सभी नंबरों को प्रिंट करना चाहिए

ऐसा इसलिए है क्योंकि 64-बिट JIT कंपाइलर टेल कॉल ऑप्टिमाइजेशन लागू करता है , जबकि 32-बिट JIT नहीं करता है।

दुर्भाग्य से मुझे इसे सत्यापित करने के लिए हाथ से 64-बिट मशीन नहीं मिली है, लेकिन यह विधि टेल-कॉल ऑप्टिमाइज़ेशन के लिए सभी शर्तों को पूरा करती है। अगर किसी के पास एक है तो मुझे यह देखने के लिए दिलचस्पी होगी कि क्या यह सच है।


10
रिलीज मोड में संकलित किया जाना है, लेकिन सबसे निश्चित रूप से x64 = पर काम करता है)
नील विलियम्स

3
जब वीएस 2010 सभी मौजूदा जेआईटी तब रिलीज़ मोड में TCO करेंगे तब से अपना जवाब अपडेट करने लायक हो सकता है
ShuggyCoUk

3
32-बिट WinXP पर VS2010 बीटा 1 पर बस कोशिश की गई। अभी भी एक StackOverflowException प्राप्त करें।
स्क्विलमैन

130
StackOverflowException के लिए +1
कैल्विनलफ

7
कि ++वहाँ पूरी तरह से मुझे फेंक दिया। क्या आप Rec(i + 1)एक सामान्य व्यक्ति की तरह नहीं कह सकते हैं ?
विन्यासकर्ता

111

यह असाइन करें!


यह वह है जिसे मैं पार्टियों में पूछना पसंद करता हूं (शायद यही वजह है कि मुझे अब आमंत्रित नहीं किया जाता है):

क्या आप निम्नलिखित संकलन कोड बना सकते हैं?

    public void Foo()
    {
        this = new Teaser();
    }

एक आसान धोखा हो सकता है:

string cheat = @"
    public void Foo()
    {
        this = new Teaser();
    }
";

लेकिन असली समाधान यह है:

public struct Teaser
{
    public void Foo()
    {
        this = new Teaser();
    }
}

इसलिए यह एक छोटा सा तथ्य है कि मूल्य प्रकार (संरचना) उनके thisचर को फिर से असाइन कर सकते हैं ।


3
C ++ क्लासेस भी ऐसा कर सकते हैं ... जैसा कि मैंने हाल ही में खोजा है, केवल वास्तव में एक अनुकूलन के लिए इसका उपयोग करने की कोशिश में चिल्लाया जा रहा है: पी
एमपीएन

1
मैं वास्तव में इन-प्लेस नए का उपयोग कर रहा था। बस सभी क्षेत्रों को अद्यतन करने के लिए एक कुशल तरीका चाहता था :)
एमपीएन

70
यह भी एक धोखा है: //this = new Teaser();:-)
एंड्रयूजैकसनजेडए

17
:-) मैं अपने उत्पादन कोड में उन चीटियों को पसंद करूंगा, जो इस पुनर्मूल्यांकन को खत्म करने की तुलना में ...
उमर मोर

2
सीएलआर के माध्यम से सी # के माध्यम से: उन्होंने इसे बनाया कारण यह है कि आप किसी अन्य निर्माता में एक संरचना के पैरामीटर रहित निर्माता को कॉल कर सकते हैं। यदि आप किसी संरचना के केवल एक मूल्य को शुरू करना चाहते हैं और अन्य मान शून्य / शून्य (डिफ़ॉल्ट) चाहते हैं, तो आप लिख सकते हैं public Foo(int bar){this = new Foo(); specialVar = bar;}। यह कुशल नहीं है और वास्तव में उचित नहीं है ( specialVarदो बार सौंपा गया है), लेकिन सिर्फ FYI करें। (यही कारण है कि पुस्तक में दिया गया है, मुझे नहीं पता कि हमें बस क्यों नहीं करना चाहिए public Foo(int bar) : this())
kizzx2

100

कुछ साल पहले, जब हम वफादारी कार्यक्रम पर काम कर रहे थे, हमारे पास ग्राहकों को दिए गए अंकों की मात्रा के साथ एक मुद्दा था। मुद्दा कास्टिंग / इंट टू इंट में परिवर्तित करने से संबंधित था।

नीचे दिए गए कोड में:

double d = 13.6;

int i1 = Convert.ToInt32(d);
int i2 = (int)d;

क्या i1 == i2 ?

यह पता चला है कि i1! = I2। कन्वर्ट और कास्ट ऑपरेटर में विभिन्न गोलाई नीतियों के कारण वास्तविक मूल्य हैं:

i1 == 14
i2 == 13

हमेशा Math.Ceiling () या Math.Floor () या (Math.Round के साथ MidpointRounding जो हमारी आवश्यकताओं को पूरा करता है) को कॉल करना बेहतर होता है

int i1 = Convert.ToInt32( Math.Ceiling(d) );
int i2 = (int) Math.Ceiling(d);

44
पूर्णांक तक कास्टिंग गोल नहीं होती है, यह बस इसे काट देती है (प्रभावी रूप से हमेशा नीचे की ओर गोल होती है)। तो यह पूर्ण समझ में आता है।
मैक्स शिमलिंग

57
@ मोम: हाँ, लेकिन कन्वर्ट राउंड क्यों होता है?
स्टीफन स्टाइनगर

18
@ स्तेफ़ान स्टाइनगर यदि यह सब किया जाता था, तो पहले स्थान पर इसका कोई कारण नहीं होगा, क्या यह होगा? यह भी ध्यान दें कि वर्ग का नाम कन्वर्ट नहीं कास्ट है।
बग-ए-लॉट

3
VB में: CInt () राउंड। फिक्स () ट्रंकट्स। मुझे जला एक बार ( blog.wassupy.com/2006/01/i-can-believe-it-not-truncating.html )
माइकल हरेन

74

जब एनम फ़ंक्शन ओवरलोड होता है तब भी उन्हें 0 पूर्णांक बनाना चाहिए।

मैं जानता था कि सी # कोर टीम के अंकन को मैपिंग के लिए 0 से एनुम किया गया है, लेकिन फिर भी, यह उतना ही ओथोगोनल नहीं है जितना होना चाहिए। Npgsql से उदाहरण ।

परीक्षण उदाहरण:

namespace Craft
{
    enum Symbol { Alpha = 1, Beta = 2, Gamma = 3, Delta = 4 };


   class Mate
    {
        static void Main(string[] args)
        {

            JustTest(Symbol.Alpha); // enum
            JustTest(0); // why enum
            JustTest((int)0); // why still enum

            int i = 0;

            JustTest(Convert.ToInt32(0)); // have to use Convert.ToInt32 to convince the compiler to make the call site use the object version

            JustTest(i); // it's ok from down here and below
            JustTest(1);
            JustTest("string");
            JustTest(Guid.NewGuid());
            JustTest(new DataTable());

            Console.ReadLine();
        }

        static void JustTest(Symbol a)
        {
            Console.WriteLine("Enum");
        }

        static void JustTest(object o)
        {
            Console.WriteLine("Object");
        }
    }
}

18
वाह यह मेरे लिए एक नई बात है। यह भी स्पष्ट है कि ConverTo.ToIn32 () कैसे काम करता है, लेकिन (int) 0 को कास्टिंग नहीं करता है। और कोई अन्य संख्या> 0 काम करता है। ("काम करता है" से मेरा मतलब है कि ऑब्जेक्ट ओवरलोड कहलाता है।)
लुकास

इस व्यवहार के इर्द-गिर्द अच्छी प्रथाओं को लागू करने के लिए एक सिफारिश कोड विश्लेषण नियम है: msdn.microsoft.com/en-us/library/ms182149%28VS.80%29.aspx उस लिंक में 0-मानचित्रण के काम करने के तरीके का भी अच्छा विवरण है। ।
क्रिस क्लार्क

1
@ क्रिस क्लार्क: मैंने एनम सिंबल पर कोई नहीं = 0 डालने की कोशिश की। फिर भी कंपाइलर 0 और यहां तक ​​कि (int) 0 के लिए एन्युम चुनता है
माइकल ब्यून

2
IMO में उन्हें एक कीवर्ड पेश करना चाहिए noneजिसे किसी भी एनम में परिवर्तित किया जा सकता है, और 0 को हमेशा एक इंटम बना दिया जाता है और एक एनुम को अंतर्निहित नहीं किया जाता है।
कोडइन्चोस

5
ConverTo.ToIn32 () काम करता है क्योंकि यह परिणाम है कोई संगति स्थिर नहीं है। और केवल संकलित स्थिरांक 0 एक ईनाम के लिए परिवर्तनीय है। .Net के पहले के संस्करणों में भी केवल शाब्दिक 0को एनम के लिए परिवर्तनीय होना चाहिए था। एरिक लिपर्ट
CodesInChaos

67

यह अब तक देखे गए सबसे असामान्य तरीकों में से एक है (बेशक यहां लोगों से अलग!):

public class Turtle<T> where T : Turtle<T>
{
}

यह आपको इसकी घोषणा करने देता है लेकिन इसका कोई वास्तविक उपयोग नहीं है, क्योंकि यह हमेशा आपको केंद्र में एक और कछुए के साथ जो भी सामान रखने के लिए कहेंगे।

[मजाक] मुझे लगता है कि यह सभी तरह से नीचे कछुए है ... [/ मजाक]


34
आप उदाहरणों, हालांकि बना सकते हैं:class RealTurtle : Turtle<RealTurtle> { } RealTurtle t = new RealTurtle();
मार्क Gravell

24
वास्तव में। यह वह पैटर्न है जिसका उपयोग जावा एनम बड़े प्रभाव में करता है। मैं प्रोटोकॉल बफ़र्स में भी इसका इस्तेमाल करता हूं।
जॉन स्कीट

6
RCIX, ओह हाँ यह है।
जोशुआ

8
मैंने फैंसी जेनेरिक सामान में इस पैटर्न का काफी इस्तेमाल किया है। यह चीजों को एक सही ढंग से टाइप किए गए क्लोन, या स्वयं के उदाहरण बनाने की अनुमति देता है।
लूसो

20
यह 'उत्सुकता से आवर्ती टेम्पलेट पैटर्न' है en.wikipedia.org/wiki/Curiously_recurring_template_pattern
porges

65

यहाँ एक मैं केवल हाल ही में पता चला है ...

interface IFoo
{
   string Message {get;}
}
...
IFoo obj = new IFoo("abc");
Console.WriteLine(obj.Message);

उपरोक्त पहली नज़र में पागल लगता है, लेकिन है वास्तव में कानूनी है। नहीं , वास्तव में (हालांकि मैंने एक महत्वपूर्ण भाग को याद किया है, लेकिन यह कुछ भी हैक करने योग्य नहीं है जैसे "एक वर्ग जोड़ें IFoo" या "एक usingबिंदु IFooपर एक उपनाम जोड़ना" कक्षा")।

देखें कि आप यह पता लगा सकते हैं कि क्यों, फिर: कौन कहता है कि आप एक इंटरफेस को इंस्टेंट नहीं कर सकते हैं?


1
"उपनाम का उपयोग" के लिए +1 - मैं कभी नहीं पता था कि तुम कर सकते हो कि !
डेविड

COM इंटरॉप :-) के लिए कंपाइलर में हैक :-)
आयन टोडरेल

कमीने! आप कम से कम "कुछ परिस्थितियों में" कह सकते हैं ... मेरा संकलक अव्यवस्थित करता है!
एमए हनिन

56

जब एक बूलियन न तो सच है और न ही गलत है?

बिल ने पाया कि आप एक बूलियन को हैक कर सकते हैं ताकि यदि ए ट्रू और बी ट्रू है, (ए और बी) गलत है।

हैक किए गए बुलियन


134
जब यह FILE_NOT_FOUND हो, तो अवश्य!
Greg में ग्रेग

12
यह दिलचस्प है क्योंकि इसका मतलब है, गणितीय रूप से बोलना, कि सी # में कोई भी बयान साबित नहीं होता है। ओह।
साइमन जॉनसन

20
किसी दिन मैं एक कार्यक्रम लिखूंगा जो इस व्यवहार पर निर्भर करता है, और सबसे अंधेरे नरक के राक्षस मेरे लिए एक स्वागत योग्य तैयारी करेंगे। Bwahahahahaha!
जेफरी एल व्हाइटलेज

18
यह उदाहरण बिटकॉइन का उपयोग करता है, न कि तार्किक ऑपरेटरों का। यह आश्चर्य की बात कैसे है?
जोश ली

6
खैर, वह संरचना के लेआउट को हैक करता है, निश्चित रूप से आपको अजीब परिणाम मिलेंगे, यह आश्चर्यजनक या अप्रत्याशित नहीं है!
इयोन टोडिएरेल

47

मैं पार्टी में थोड़ा देरी से पहुँच रहा हूँ, लेकिन मुझे तीन चार पाँच मिले हैं:

  1. यदि आप किसी ऐसे नियंत्रण पर चालान भेज देते हैं जो लोड / दिखाया नहीं गया है, तो यह गलत कहेगा - और यदि आप इसे किसी अन्य थ्रेड से बदलने का प्रयास करते हैं ( तो इसका संदर्भ देने के लिए समाधान है) नियंत्रण)।

  2. एक और जिसने मुझे फंसाया है वह है:

    enum MyEnum
    {
        Red,
        Blue,
    }

    यदि आप किसी अन्य असेंबली में MyEnum.Red.ToString () की गणना करते हैं, और किसी के बीच में किसी ने आपके नन:

    enum MyEnum
    {
        Black,
        Red,
        Blue,
    }

    रनटाइम पर, आपको "ब्लैक" मिलेगा।

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

  4. यदि आप किसी अन्य असेंबली से किसी इंटरफ़ेस की नई विधि को कार्यान्वित करते हैं, लेकिन आप उस असेंबली के पुराने संस्करण को संदर्भित करते हुए पुनर्निर्माण करते हैं, तो आपको एक TypeLoadException ('NewMethod' का कोई कार्यान्वयन नहीं मिलता है), भले ही आपने इसे लागू किया हो ( यहाँ देखें )।

  5. शब्दकोश <,>: "जिस क्रम में आइटम वापस किए जाते हैं वह अपरिभाषित है"। यह भयानक है , क्योंकि यह आपको कभी-कभी काट सकता है, लेकिन दूसरों को काम कर सकता है, और यदि आपने अभी आँख बंद करके मान लिया है कि शब्दकोश अच्छा खेलने वाला है ("मुझे ऐसा क्यों नहीं करना चाहिए? मैंने सोचा था, सूची करता है"), आपके पास वास्तव में है इससे पहले कि आप अंततः अपनी धारणा पर सवाल उठाना शुरू करें, उसमें आपकी नाक है।


6
# 2 एक दिलचस्प उदाहरण है। Enums अभिन्न मूल्यों के लिए कंपाइलर मैपिंग हैं। इसलिए, भले ही आपने उन्हें स्पष्ट रूप से मान निर्दिष्ट नहीं किया है, कंपाइलर ने MyEnum.Red = 0 और MyEnum.Blue = 1. परिणामस्वरूप, जब आपने ब्लैक को जोड़ा, तो आपने मान को 0 से लाल से ब्लैक में मैप करने के लिए फिर से परिभाषित किया। मुझे संदेह है कि यह समस्या अन्य उपयोगों में भी प्रकट होगी, जैसे कि धारावाहिककरण।
LBushkin

3
आवश्यक चालान के लिए +1। हमारे यहां हम लाल = 1, ब्लू = 2 जैसे शब्दों को स्पष्ट रूप से मान देना पसंद करते हैं, इसलिए नए को पहले या बाद में डाला जा सकता है क्योंकि इसके परिणामस्वरूप हमेशा समान मूल्य होगा। यदि आप डेटाबेस के लिए मानों को सहेज रहे हैं तो यह विशेष रूप से आवश्यक है।
TheVillageIdiot

53
मैं असहमत हूं कि # 5 एक "एज केस" है। जब आप मान सम्मिलित करते हैं तो डिक्शनरी के आधार पर परिभाषित आदेश नहीं होना चाहिए। यदि आप एक परिभाषित आदेश चाहते हैं, तो एक सूची का उपयोग करें, या एक कुंजी का उपयोग करें जिसे इस तरह से सॉर्ट किया जा सकता है जो आपके लिए उपयोगी हो, या पूरी तरह से अलग डेटा संरचना का उपयोग करें।
वेज

21
@ शायद, SortedDictionary की तरह?
एलोन गुरिलानेक

4
# 3 ऐसा होता है क्योंकि स्थिरांक को शाब्दिक रूप से हर जगह डाला जाता है जिसका वे उपयोग करते हैं (सी # में, कम से कम)। आपके पूर्ववर्ती ने पहले ही इस पर ध्यान दिया होगा, यही वजह है कि उन्होंने केवल-संपत्ति का उपयोग किया। हालांकि, एक पठनीय चर (एक कास्ट के विपरीत) बस के रूप में अच्छी तरह से काम करेगा।
30:09

33

VB.NET, nullables और टर्नरी ऑपरेटर:

Dim i As Integer? = If(True, Nothing, 5)

मुझे डिबग करने में कुछ समय लगा, क्योंकि मुझे iइसमें शामिल होने की उम्मीद थीNothing

मेरे पास वास्तव में क्या है? 0

यह आश्चर्यजनक है लेकिन वास्तव में "सही" व्यवहार: NothingVB.NET nullमें CLR के समान नहीं है : संदर्भ के आधार पर या Nothingतो इसका मतलब nullया default(T)मूल्य प्रकार के Tलिए हो सकता है। उपरोक्त मामले में, Ifinfers Integerकी आम प्रकार के रूप में Nothingऔर 5, इसलिए, इस मामले में, Nothingइसका मतलब है 0


काफी दिलचस्प है, मैं इस जवाब को खोजने में विफल रहा, इसलिए मुझे एक प्रश्न बनाना पड़ा । खैर, कौन जानता था कि जवाब इस धागे में है?
GSerg

28

मुझे एक दूसरा वास्तव में अजीब कोने का मामला मिला जो मेरे पहले एक लंबे शॉट से धड़कता है।

String.Equals Method (String, String, StringComparison) वास्तव में साइड इफेक्ट मुक्त नहीं है।

मैं कोड के एक ब्लॉक पर काम कर रहा था, जो किसी फ़ंक्शन के शीर्ष पर एक पंक्ति में स्वयं था:

stringvariable1.Equals(stringvariable2, StringComparison.InvariantCultureIgnoreCase);

उस लाइन को हटाने से प्रोग्राम में कहीं और स्टैक ओवरफ्लो हो जाता है।

कोड एक एफ़ैडवाशेलड इवेंट में सार के लिए एक हैंडलर स्थापित करने की कोशिश कर रहा था और करने की कोशिश कर रहा था

if (assemblyfilename.EndsWith("someparticular.dll", StringComparison.InvariantCultureIgnoreCase))
{
    assemblyfilename = "someparticular_modified.dll";
}

अब तक मुझे आपको बताना नहीं चाहिए था। एक संस्कृति का उपयोग करना जो पहले एक स्ट्रिंग तुलना में उपयोग नहीं किया गया है, एक विधानसभा लोड का कारण बनता है। InvariantCulture इसका अपवाद नहीं है।


मुझे लगता है कि "असेंबली लोड करना" एक साइड इफेक्ट है, क्योंकि आप इसे एअरवॉल्डवॉल्ड के साथ देख सकते हैं!
याकूब क्राल

2
वाह। यह अनुचर के पैर में एक सही शॉट है। मुझे लगता है कि एक FirstAssemblyLoad हैंडलर लिखने से बहुत सारे आश्चर्य हो सकते हैं।
19

20

यहां एक उदाहरण है कि आप एक संरचना कैसे बना सकते हैं जो त्रुटि संदेश का कारण बनता है "संरक्षित मेमोरी को पढ़ने या लिखने का प्रयास किया। यह अक्सर एक संकेत है कि अन्य मेमोरी भ्रष्ट है"। सफलता और असफलता के बीच का अंतर बहुत सूक्ष्म है।

निम्नलिखित इकाई परीक्षण समस्या को प्रदर्शित करता है।

देखें कि क्या आप गलत काम कर सकते हैं।

    [Test]
    public void Test()
    {
        var bar = new MyClass
        {
            Foo = 500
        };
        bar.Foo += 500;

        Assert.That(bar.Foo.Value.Amount, Is.EqualTo(1000));
    }

    private class MyClass
    {
        public MyStruct? Foo { get; set; }
    }

    private struct MyStruct
    {
        public decimal Amount { get; private set; }

        public MyStruct(decimal amount) : this()
        {
            Amount = amount;
        }

        public static MyStruct operator +(MyStruct x, MyStruct y)
        {
            return new MyStruct(x.Amount + y.Amount);
        }

        public static MyStruct operator +(MyStruct x, decimal y)
        {
            return new MyStruct(x.Amount + y);
        }

        public static implicit operator MyStruct(int value)
        {
            return new MyStruct(value);
        }

        public static implicit operator MyStruct(decimal value)
        {
            return new MyStruct(value);
        }
    }

मेरा सिर दर्द करता है ... यह काम क्यों नहीं करता है?
जासं

2
हम्म ने यह कुछ महीने पहले लिखा था, लेकिन मुझे याद नहीं है कि वास्तव में ऐसा क्यों हुआ।
cbp

10
एक कंपाइलर बग जैसा दिखता है; += 500कॉल: ldc.i4 500(कोई Int32 के रूप में 500 धक्का), तो call valuetype Program/MyStruct Program/MyStruct::op_Addition(valuetype Program/MyStruct, valuetype [mscorlib]System.Decimal)- तो यह तो एक के रूप में व्यवहार करता है decimalकिसी भी रूपांतरण के बिना (96-बिट)। यदि आप इसका उपयोग करते हैं += 500Mतो यह सही हो जाता है। यह बस ऐसा लगता है कि संकलक को लगता है कि यह इसे एक तरह से कर सकता है (संभवतः अंतर्निहित इंट ऑपरेटर के कारण) और फिर इसे दूसरे तरीके से करने का फैसला करता है।
मार्क Gravell

1
डबल पोस्ट के लिए क्षमा करें, यहां एक अधिक योग्य विवरण दिया गया है। मैं इसे जोड़ूंगा, मैं इसके द्वारा थोड़ा सा हो गया हूं और यह बेकार है, भले ही मैं समझता हूं कि ऐसा क्यों होता है। मेरे लिए यह संरचना / मूल्यांकन का एक दुर्भाग्यपूर्ण सीमा है। बाइट्स। एन्टॉपिक
बेनेट डिल

2
@ कंपाइलर त्रुटियां होने या मूल संरचना को प्रभावित न करने वाले संशोधन ठीक हैं। एक पहुंच उल्लंघन काफी अलग जानवर है। यदि आप सिर्फ सुरक्षित शुद्ध प्रबंधित कोड लिख रहे हैं तो रनटाइम को कभी भी फेंकना नहीं चाहिए।
कोडइन्चोसोस

18

C # सरणियों और सूचियों के बीच रूपांतरणों का समर्थन करता है जब तक कि सरणियाँ बहुआयामी नहीं होती हैं और प्रकारों के बीच एक वंशानुक्रम संबंध होता है और प्रकार संदर्भ प्रकार होते हैं

object[] oArray = new string[] { "one", "two", "three" };
string[] sArray = (string[])oArray;

// Also works for IList (and IEnumerable, ICollection)
IList<string> sList = (IList<string>)oArray;
IList<object> oList = new string[] { "one", "two", "three" };

ध्यान दें कि यह काम नहीं करता है:

object[] oArray2 = new int[] { 1, 2, 3 }; // Error: Cannot implicitly convert type 'int[]' to 'object[]'
int[] iArray = (int[])oArray2;            // Error: Cannot convert type 'object[]' to 'int[]'

11
IList <T> उदाहरण सिर्फ एक कास्ट है, क्योंकि स्ट्रिंग [] पहले से ही ICloneable, IList, ICollection, IEnumerable, IList <string>, ICollection <string>, और IEnumableable <string> को लागू करता है।
लुकास

15

यह मैं दुर्घटना से सामना किया है सबसे अजीब है:

public class DummyObject
{
    public override string ToString()
    {
        return null;
    }
}

निम्नानुसार उपयोग किया जाता है:

DummyObject obj = new DummyObject();
Console.WriteLine("The text: " + obj.GetType() + " is " + obj);

फेंक देंगे NullReferenceException। कॉल करने के लिए C # संकलक द्वारा कई परिवर्धन संकलित किए जाते हैं String.Concat(object[])। .NET 4 से पहले, कॉनैट के बस ओवरलोड में एक बग है जहां ऑब्जेक्ट को शून्य के लिए जांचा जाता है, लेकिन ToString () का परिणाम नहीं है:

object obj2 = args[i];
string text = (obj2 != null) ? obj2.ToString() : string.Empty;
// if obj2 is non-null, but obj2.ToString() returns null, then text==null
int length = text.Length;

यह ECMA-334 .414.7.4 द्वारा एक बग है:

जब एक या दोनों ऑपरेंड प्रकार के होते हैं, तो बाइनरी + ऑपरेटर स्ट्रिंग कॉन्सेटेशन करता है string। यदि स्ट्रिंग के संघनन का एक संचालन है null, तो एक खाली स्ट्रिंग प्रतिस्थापित किया जाता है। अन्यथा, किसी भी गैर-स्ट्रिंग ऑपरेंड को ToStringटाइप से विरासत में मिली वर्चुअल विधि को लागू करके इसके स्ट्रिंग प्रतिनिधित्व में बदल दिया जाता है objectयदि ToStringरिटर्न null, एक खाली स्ट्रिंग प्रतिस्थापित किया जाता है।


3
हम्म, लेकिन मैं इस गलती की कल्पना कर सकता हूं क्योंकि .ToStringवास्तव में कभी भी अशक्त नहीं होना चाहिए, लेकिन स्ट्रिंग। फिर भी और ढांचे में त्रुटि।
डायकम

12

दिलचस्प है - जब मैंने पहली बार देखा कि मैंने यह मान लिया था कि कुछ ऐसा है जो C # संकलक के लिए जाँच रहा था, लेकिन भले ही आप IL को सीधे हस्तक्षेप के किसी भी अवसर को हटाने के लिए उत्सर्जित करते हों, फिर भी इसका अर्थ है कि यह वास्तव में newobjऑप-कोड है जो कि कर रहा है जाँच।

var method = new DynamicMethod("Test", null, null);
var il = method.GetILGenerator();

il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Newarr, typeof(char));
il.Emit(OpCodes.Newobj, typeof(string).GetConstructor(new[] { typeof(char[]) }));

il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Newarr, typeof(char));
il.Emit(OpCodes.Newobj, typeof(string).GetConstructor(new[] { typeof(char[]) }));

il.Emit(OpCodes.Call, typeof(object).GetMethod("ReferenceEquals"));
il.Emit(OpCodes.Box, typeof(bool));
il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] { typeof(object) }));

il.Emit(OpCodes.Ret);

method.Invoke(null, null);

यह भी बराबरी करता है trueकि आप किसके खिलाफ जाँच करते हैं string.Empty, इसका मतलब है कि इस ऑप-कोड में खाली तारों को जोड़ने के लिए विशेष व्यवहार होना चाहिए।


स्मार्ट ब्लेक या कुछ भी नहीं है, लेकिन क्या आपने रिफ्लेक्टर के बारे में सुना है ? इस तरह के मामलों में यह काफी आसान है;
आरसीआईएक्स

3
तुम होशियार नहीं हो; आप इस बिंदु को याद कर रहे हैं - मैं इस एक मामले के लिए विशिष्ट IL उत्पन्न करना चाहता था। और वैसे भी, यह देखते हुए कि परावर्तन। इस प्रकार के परिदृश्य के लिए बहुत अच्छा है, यह संभवतः C # में एक प्रोग्राम लिखने के रूप में जल्दी है, फिर रिफ्लेक्टर खोलने, द्विआधारी खोजने, विधि खोजने, आदि ... और मुझे भी नहीं करना है यह करने के लिए आईडीई छोड़ दें।
ग्रेग बीच

10
Public Class Item
   Public ID As Guid
   Public Text As String

   Public Sub New(ByVal id As Guid, ByVal name As String)
      Me.ID = id
      Me.Text = name
   End Sub
End Class

Public Sub Load(sender As Object, e As EventArgs) Handles Me.Load
   Dim box As New ComboBox
   Me.Controls.Add(box)          'Sorry I forgot this line the first time.'
   Dim h As IntPtr = box.Handle  'Im not sure you need this but you might.'
   Try
      box.Items.Add(New Item(Guid.Empty, Nothing))
   Catch ex As Exception
      MsgBox(ex.ToString())
   End Try
End Sub

आउटपुट "संरक्षित मेमोरी को पढ़ने का प्रयास किया जाता है। यह एक संकेत है कि अन्य मेमोरी भ्रष्ट है।"


1
दिलचस्प! एक संकलक बग की तरह लगता है, हालांकि; मैंने C # पोर्ट किया है और यह ठीक काम करता है। कहा कि, लोड में अपवादों के साथ बहुत सारे मुद्दे हैं, और यह डिबगर के साथ / बिना अलग व्यवहार करता है - आप डिबगर के साथ पकड़ सकते हैं, लेकिन बिना (कुछ मामलों में)।
मार्क Gravell

क्षमा करें, मैं भूल गया, आपको कॉम्बो बॉक्स को फॉर्म में आने से पहले जोड़ना होगा।
जोशुआ

यह एक आंतरिक आंतरिक संचार तंत्र के कुछ प्रकार के रूप में SEH का उपयोग करके डायलॉग आरंभीकरण के साथ करना है? मैं Win32 में ऐसा कुछ याद करता हूं।
डैनियल इयरविकर

1
ऊपर यही समस्या cbp है। लौटाई जा रही क़ीमत एक प्रति है, इसलिए कहा गया है कि प्रतिलिपि से उपजी किसी भी संपत्ति के किसी भी संदर्भ बिट-बाल्टी भूमि के लिए नेतृत्व कर रहे हैं ... bytes.com/topic/net/answers/…
Bennett Dill

1
नहीं। यहाँ कोई संरचना नहीं हैं। मैंने वास्तव में इसे डिबग किया। यह विलंबित दुर्घटना के कारण देशी कॉम्बो बॉक्स के सूची आइटम संग्रह में एक NULL जोड़ता है।
जोशुआ

10

PropertyInfo.SetValue () inums को inums, ints को nullable ints, enums को nullable enums, लेकिन ints को nullable enums में असाइन कर सकते हैं।

enumProperty.SetValue(obj, 1, null); //works
nullableIntProperty.SetValue(obj, 1, null); //works
nullableEnumProperty.SetValue(obj, MyEnum.Foo, null); //works
nullableEnumProperty.SetValue(obj, 1, null); // throws an exception !!!

पूरा विवरण यहाँ


10

क्या होगा यदि आपके पास एक सामान्य वर्ग है जिसमें ऐसी विधियाँ हैं जिन्हें प्रकार के तर्कों के आधार पर अस्पष्ट बनाया जा सकता है? मैं हाल ही में दो-तरफा शब्दकोश लिखकर इस स्थिति में आया था। मैं सममित Get()तरीके लिखना चाहता था जो कि जो भी तर्क पारित किया गया था, उसके विपरीत लौटेगा। कुछ इस तरह:

class TwoWayRelationship<T1, T2>
{
    public T2 Get(T1 key) { /* ... */ }
    public T1 Get(T2 key) { /* ... */ }
}

यदि आप एक उदाहरण बनाते हैं, जहां सभी अच्छे हैं T1और T2विभिन्न प्रकार हैं:

var r1 = new TwoWayRelationship<int, string>();
r1.Get(1);
r1.Get("a");

लेकिन अगर T1और T2समान हैं (और शायद अगर एक दूसरे का उपवर्ग था), तो यह एक संकलक त्रुटि है:

var r2 = new TwoWayRelationship<int, int>();
r2.Get(1);  // "The call is ambiguous..."

दिलचस्प है, दूसरे मामले में अन्य सभी विधियां अभी भी प्रयोग करने योग्य हैं; यह केवल अब-अस्पष्ट विधि को कॉल करता है जो कंपाइलर त्रुटि का कारण बनता है। दिलचस्प मामला है, अगर थोड़ी संभावना नहीं है और अस्पष्ट है।


विधि अधिभार के विरोधी इसे पसंद करेंगे ^ ^।
क्रिश्चियन क्लाऊसर

1
मुझे नहीं पता, इससे मुझे पूरी समझ है।
स्कॉट व्हिटलॉक

10

सी # एक्सेसिबिलिटी पज़्लर


निम्न व्युत्पन्न वर्ग अपने आधार वर्ग से एक निजी क्षेत्र तक पहुँच रहा है , और संकलक चुपचाप दूसरी तरफ देखता है:

public class Derived : Base
{
    public int BrokenAccess()
    {
        return base.m_basePrivateField;
    }
}

क्षेत्र वास्तव में निजी है:

private int m_basePrivateField = 0;

यह अनुमान लगाने की परवाह करें कि हम इस तरह के कोड को कैसे संकलित कर सकते हैं?

उत्तर


चाल को Derivedभीतर के वर्ग के रूप में घोषित करना है Base:

public class Base
{
    private int m_basePrivateField = 0;

    public class Derived : Base
    {
        public int BrokenAccess()
        {
            return base.m_basePrivateField;
        }
    }
}

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


यह वास्तव में अच्छी तरह से प्रलेखित है; msdn.microsoft.com/en-us/library/ms173120%28VS.80%29.aspx । यह कई बार एक उपयोगी विशेषता हो सकती है, खासकर अगर बाहरी वर्ग स्थिर है।

हाँ - बेशक यह प्रलेखित है। हालांकि, बहुत कम लोगों ने इस पहेली को हल किया है इसलिए मुझे लगा कि यह सामान्य ज्ञान का एक टुकड़ा है।
ओमर मोर

2
लगता है कि आप एक आंतरिक वर्ग अपने मालिक वारिस होने के द्वारा एक ढेर अतिप्रवाह की एक बहुत मजबूत संभावना है ...
जॅमी Treworgy

फिर भी एक अन्य समान (और पूरी तरह से सही) मामला यह है कि एक वस्तु एक ही प्रकार की दूसरी वस्तु के निजी सदस्य तक पहुंच सकती है:class A { private int _i; public void foo(A other) { int res = other._i; } }
ओलिवियर जैकोत-डेसकोम्बेव

10

बस आज एक अच्छी छोटी बात मिली:

public class Base
{
   public virtual void Initialize(dynamic stuff) { 
   //...
   }
}
public class Derived:Base
{
   public override void Initialize(dynamic stuff) {
   base.Initialize(stuff);
   //...
   }
}

यह संकलन त्रुटि करता है।

'इनिशियलाइज़' पद्धति को कॉल को गतिशील रूप से भेजने की आवश्यकता है, लेकिन ऐसा नहीं हो सकता क्योंकि यह एक बेस एक्सेस अभिव्यक्ति का हिस्सा है। गतिशील तर्कों को आधार बनाने या आधार पहुंच को समाप्त करने पर विचार करें।

अगर मैं आधार लिखता हूं। Initialize (वस्तु के रूप में सामान); यह पूरी तरह से काम करता है, हालांकि यह एक "जादू शब्द" प्रतीत होता है, क्योंकि यह बिल्कुल वैसा ही करता है, सब कुछ अभी भी गतिशील के रूप में प्राप्त होता है ...


8

हम जिस API का उपयोग कर रहे हैं, एक डोमेन ऑब्जेक्ट वापस करने वाली विधियाँ एक विशेष "null ऑब्जेक्ट" लौटा सकती हैं। इसके कार्यान्वयन में, तुलना ऑपरेटर और Equals()विधि को वापस करने के लिए ओवरराइड किया जाता हैtrue साथ तुलना की अनुमति है null

तो इस API के उपयोगकर्ता के पास कुछ इस तरह का कोड हो सकता है:

return test != null ? test : GetDefault();

या शायद थोड़ा और अधिक क्रिया, इस तरह:

if (test == null)
    return GetDefault();
return test;

जहां GetDefault()एक विधि कुछ डिफ़ॉल्ट मान लौटा रही है जिसका उपयोग हम इसके बजाय करना चाहते हैं null। आश्चर्य है कि जब मैं ReSharper का उपयोग कर रहा था, तो उसने मुझे मारा और निम्नलिखित में से किसी एक को फिर से लिखने की सिफारिश की:

return test ?? GetDefault();

यदि परीक्षण ऑब्जेक्ट एक उचित के बजाय एपीआई से लौटाया गया अशक्त ऑब्जेक्ट है null, तो कोड का व्यवहार अब बदल गया है, क्योंकि अशक्त सहवर्ती ऑपरेटर वास्तव में जांच करता है null, न कि चल रहा है operator=या नहीं Equals()


1
वास्तव में एसी # कोने का मामला नहीं है, लेकिन प्रिय स्वामी जिसने सोचा था कि?!?
रे बोयसेन

क्या यह कोड केवल अशक्त प्रकारों का उपयोग नहीं कर रहा है? इसलिए ReSharper की सिफारिश "??" उपयोग। जैसा कि रे ने कहा, मुझे नहीं लगता कि यह एक कोने का मामला होगा; या मैं गलत हूँ?
टोनी

1
हां, प्रकार अशक्त हैं - और इसके अलावा एक नलब्लॉज भी है। अगर यह एक कोने का मामला है, तो मुझे नहीं पता, लेकिन कम से कम यह एक ऐसा मामला है, जहां 'अगर (! = Null) वापस लौटना है; वापसी बी? ' 'वापसी ए' के ​​समान नहीं है? बी '। मैं बिल्कुल सहमत हूँ कि यह फ्रेमवर्क / एपीआई डिज़ाइन के साथ एक समस्या है - किसी वस्तु पर सच लौटने के लिए == अतिभारित होना निश्चित रूप से अच्छे विचार के लिए नहीं है!
टॉर लिवर

8

इस अजीब मामले पर विचार करें:

public interface MyInterface {
  void Method();
}
public class Base {
  public void Method() { }
}
public class Derived : Base, MyInterface { }

यदि Baseऔर Derivedएक ही विधानसभा में घोषित किए जाते हैं, तो संकलक Base::Methodआभासी और सील (सीआईएल में) बना देगा, भले हीBase इंटरफ़ेस को लागू नहीं करता है।

तो Baseऔर Derivedविभिन्न विधानसभाओं में कर रहे हैं, जब संकलन Derivedविधानसभा, संकलक अन्य विधानसभा में परिवर्तन नहीं होगा, तो यह एक सदस्य का परिचय देंगे में Derivedहै कि एक स्पष्ट कार्यान्वयन किया जाएगा के लिए MyInterface::Methodहै कि बस के लिए कॉल को सौंपने जाएगाBase::Method

संकलक को इंटरफ़ेस के संबंध में बहुरूपी प्रेषण का समर्थन करने के लिए ऐसा करना पड़ता है, अर्थात उसे उस विधि को आभासी बनाना पड़ता है।


यह वास्तव में अजीब लगता है। बाद में जांच करनी होगी :)
जॉन स्कीट

@ जीन स्कीट: सी # में भूमिकाओं के लिए कार्यान्वयन रणनीतियों पर शोध करते हुए मुझे यह मिला । उस एक पर अपनी प्रतिक्रिया प्राप्त करने के लिए बहुत अच्छा होगा!
जोर्डो

7

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

class Program
{
    static void Main(string[] args)
    {
        Derived d = new Derived();
        d.Property = "AWESOME";
    }
}

class Base
{
    string _baseProp;
    public virtual string Property 
    { 
        get 
        {
            return "BASE_" + _baseProp;
        }
        set
        {
            _baseProp = value;
            //do work with the base property which might 
            //not be exposed to derived types
            //here
            Console.Out.WriteLine("_baseProp is BASE_" + value.ToString());
        }
    }
}

class Derived : Base
{
    string _prop;
    public override string Property 
    {
        get { return _prop; }
        set 
        { 
            _prop = value; 
            base.Property = value;
        } //<- put a breakpoint here then mouse over BaseProperty, 
          //   and then mouse over the base.Property call inside it.
    }

    public string BaseProperty { get { return base.Property; } private set { } }
}

में रहते हुए Derivedवस्तु संदर्भ, आप एक ही व्यवहार प्राप्त कर सकते हैं जब जोड़ने base.Propertyएक घड़ी, या टाइपिंग के रूप मेंbase.Property quickwatch में।

मुझे एहसास हुआ कि क्या चल रहा था। अंत में मैं क्विकवॉच द्वारा प्रबुद्ध था। क्विकवॉच में जाने और Derivedऑब्जेक्ट डी (या ऑब्जेक्ट के संदर्भ से this) की खोज और फ़ील्ड का चयन करते हुए base, क्विकवॉच के शीर्ष पर संपादित फ़ील्ड निम्नलिखित कलाकारों को प्रदर्शित करता है:

((TestProject1.Base)(d))

जिसका मतलब है कि अगर आधार को इस तरह बदल दिया जाता है, तो कॉल होगा

public string BaseProperty { get { return ((TestProject1.Base)(d)).Property; } private set { } }

घड़ियाँ, क्विकवॉच और डिबगिंग माउस-ओवर टूलटिप्स के लिए, और फिर यह बहुरूपता पर विचार "AWESOME"करने के बजाय इसे प्रदर्शित करने के लिए समझ में आता "BASE_AWESOME"है। मैं अभी भी अनिश्चित हूं कि इसे एक कास्ट में क्यों तब्दील किया जाएगा, एक परिकल्पना यह है कि callउन मॉड्यूल के संदर्भ से उपलब्ध नहीं हो सकता है, और केवलcallvirt

किसी भी तरह, यह स्पष्ट रूप से कार्यक्षमता के मामले में कुछ भी नहीं बदलता है, Derived.BasePropertyअभी भी वास्तव में वापस आ जाएगा "BASE_AWESOME", और इस तरह यह काम पर हमारे बग की जड़ नहीं था, बस एक भ्रमित घटक था। मुझे हालांकि यह दिलचस्प लगा कि यह कैसे विकासकर्ताओं को गुमराह कर सकता है जो अपने डिबग सत्रों के दौरान उस तथ्य से अनजान होंगे, विशेषकर यदि Baseआपकी परियोजना में उजागर नहीं किया गया है, बल्कि एक 3 डी डीएलएल के रूप में संदर्भित किया गया है, जिसके परिणामस्वरूप देव बस कह रहे हैं:

"ओई, रुको..क्यों? डीएमएल कि तरह है? .. कुछ अजीब लग रहा है"


यह कुछ खास नहीं है, बस काम करने का तरीका है।
विन्यासकर्ता

7

यह शीर्ष करने के लिए बहुत मुश्किल है। मैं इसमें भाग गया जब मैं एक RealProxy कार्यान्वयन का निर्माण करने की कोशिश कर रहा था जो वास्तव में Begin / EndInvoke का समर्थन करता है (भयानक हैक के बिना ऐसा करना असंभव बनाने के लिए धन्यवाद MS)। यह उदाहरण मूल रूप से CLR में एक बग है, BeginInvoke के लिए अप्रबंधित कोड पथ यह पुष्टि नहीं करता है कि RealProxy.PStreetInvoke (और मेरा इनवॉइस ओवरराइड) से वापसी संदेश एक IAsyncTult का एक उदाहरण लौटा रहा है। एक बार जब यह वापस आ जाता है, सीएलआर अविश्वसनीय रूप से भ्रमित हो जाता है और व्हाट्स के किसी भी विचार को खो देता है, जैसा कि नीचे दिए गए परीक्षणों द्वारा दिखाया गया है।

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Proxies;
using System.Reflection;
using System.Runtime.Remoting.Messaging;

namespace BrokenProxy
{
    class NotAnIAsyncResult
    {
        public string SomeProperty { get; set; }
    }

    class BrokenProxy : RealProxy
    {
        private void HackFlags()
        {
            var flagsField = typeof(RealProxy).GetField("_flags", BindingFlags.NonPublic | BindingFlags.Instance);
            int val = (int)flagsField.GetValue(this);
            val |= 1; // 1 = RemotingProxy, check out System.Runtime.Remoting.Proxies.RealProxyFlags
            flagsField.SetValue(this, val);
        }

        public BrokenProxy(Type t)
            : base(t)
        {
            HackFlags();
        }

        public override IMessage Invoke(IMessage msg)
        {
            var naiar = new NotAnIAsyncResult();
            naiar.SomeProperty = "o noes";
            return new ReturnMessage(naiar, null, 0, null, (IMethodCallMessage)msg);
        }
    }

    interface IRandomInterface
    {
        int DoSomething();
    }

    class Program
    {
        static void Main(string[] args)
        {
            BrokenProxy bp = new BrokenProxy(typeof(IRandomInterface));
            var instance = (IRandomInterface)bp.GetTransparentProxy();
            Func<int> doSomethingDelegate = instance.DoSomething;
            IAsyncResult notAnIAsyncResult = doSomethingDelegate.BeginInvoke(null, null);

            var interfaces = notAnIAsyncResult.GetType().GetInterfaces();
            Console.WriteLine(!interfaces.Any() ? "No interfaces on notAnIAsyncResult" : "Interfaces");
            Console.WriteLine(notAnIAsyncResult is IAsyncResult); // Should be false, is it?!
            Console.WriteLine(((NotAnIAsyncResult)notAnIAsyncResult).SomeProperty);
            Console.WriteLine(((IAsyncResult)notAnIAsyncResult).IsCompleted); // No way this works.
        }
    }
}

आउटपुट:

No interfaces on notAnIAsyncResult
True
o noes

Unhandled Exception: System.EntryPointNotFoundException: Entry point was not found.
   at System.IAsyncResult.get_IsCompleted()
   at BrokenProxy.Program.Main(String[] args) 

6

मुझे यकीन नहीं है कि यदि आप कहेंगे कि यह एक विस्टा विस्टा / 7 विषमता या एक .Net विषमता है, लेकिन इसने मुझे थोड़ी देर के लिए अपना सिर खरोंच कर दिया था।

string filename = @"c:\program files\my folder\test.txt";
System.IO.File.WriteAllText(filename, "Hello world.");
bool exists = System.IO.File.Exists(filename); // returns true;
string text = System.IO.File.ReadAllText(filename); // Returns "Hello world."

Windows Vista / 7 में फ़ाइल वास्तव में लिखी जाएगी C:\Users\<username>\Virtual Store\Program Files\my folder\test.txt


2
यह वास्तव में एक विस्टा (7 नहीं, afaik) सुरक्षा वृद्धि है। लेकिन अच्छी बात यह है कि आप प्रोग्राम फाइल पथ के साथ फाइल को पढ़ और खोल सकते हैं, जबकि यदि आप एक्सप्लोरर के साथ देखते हैं तो कुछ भी नहीं है। इससे पहले कि मुझे यह पता चला, इससे पहले मुझे एक ग्राहक ने लगभग एक दिन @ काम में ले लिया।
हेनरी

यह निश्चित रूप से एक विंडोज 7 भी है। जब मैं इसमें भाग रहा था तो यही मैं उपयोग कर रहा था। मैं इसके पीछे के तर्क को समझता हूं लेकिन यह पता लगाना अभी भी निराशाजनक था।
स्पेंसर रूपोर्ट

विस्टा / विन 7 में (winXP तकनीकी रूप से भी) ऐप्स को उपयोगकर्ता-फ़ोल्डर भूमि में अपने तकनीकी रूप से उपयोगकर्ता डेटा के रूप में एक AppData फ़ोल्डर में लिखना चाहिए। एप्लिकेशन को प्रोग्रामफ़ाइल्स / विंडो / सिस्टम 32 / आदि पर कभी भी लिखना नहीं चाहिए, जब तक कि उनके पास व्यवस्थापक priveledges न हों, और उन priveledges को केवल प्रोग्राम को अपग्रेड करने / इसे अनइंस्टॉल करने या नई सुविधा स्थापित करने के लिए होना चाहिए। परंतु! अभी भी system32 / windows / etc पर लिखना नहीं है :) यदि आपने उस कोड को एडमिन के रूप में चलाया है (राइट क्लिक> एडमिन के रूप में रन करें) यह सैद्धांतिक रूप से प्रोग्राम फाइल ऐप फ़ोल्डर में लिखना चाहिए।
स्टीव सैफूएच

वर्चुअलाइजेशन की तरह लगता है - crispybit.spaces.live.com/blog/cns
कॉलिन नेवेल

6

क्या आपने कभी सोचा है कि C # कंपाइलर अमान्य CIL उत्पन्न कर सकता है? इसे चलाएं और आपको एक मिलेगा TypeLoadException:

interface I<T> {
  T M(T p);
}
abstract class A<T> : I<T> {
  public abstract T M(T p);
}
abstract class B<T> : A<T>, I<int> {
  public override T M(T p) { return p; }
  public int M(int p) { return p * 2; }
}
class C : B<int> { }

class Program {
  static void Main(string[] args) {
    Console.WriteLine(new C().M(42));
  }
}

मैं नहीं जानता कि यह C # 4.0 संकलक में कैसे किराए पर है।

संपादित करें : यह मेरे सिस्टम से आउटपुट है:

C:\Temp>type Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1 {

  interface I<T> {
    T M(T p);
  }
  abstract class A<T> : I<T> {
    public abstract T M(T p);
  }
  abstract class B<T> : A<T>, I<int> {
    public override T M(T p) { return p; }
    public int M(int p) { return p * 2; }
  }
  class C : B<int> { }

  class Program {
    static void Main(string[] args) {
      Console.WriteLine(new C().M(11));
    }
  }

}
C:\Temp>csc Program.cs
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.1
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.


C:\Temp>Program

Unhandled Exception: System.TypeLoadException: Could not load type 'ConsoleAppli
cation1.C' from assembly 'Program, Version=0.0.0.0, Culture=neutral, PublicKeyTo
ken=null'.
   at ConsoleApplication1.Program.Main(String[] args)

C:\Temp>peverify Program.exe

Microsoft (R) .NET Framework PE Verifier.  Version  3.5.30729.1
Copyright (c) Microsoft Corporation.  All rights reserved.

[token  0x02000005] Type load failed.
[IL]: Error: [C:\Temp\Program.exe : ConsoleApplication1.Program::Main][offset 0x
00000001] Unable to resolve token.
2 Error(s) Verifying Program.exe

C:\Temp>ver

Microsoft Windows XP [Version 5.1.2600]

मेरे लिए C # 3.5 कंपाइलर और C # 4 कंपाइलर ... दोनों के साथ काम करता है ...
Jon Skeet

मेरे सिस्टम में, यह काम नहीं करता है। मैं प्रश्न में आउटपुट पेस्ट करूँगा।
जोर्डो

यह मेरे लिए .NET 3.5 में विफल रहा (4.0 परीक्षण के लिए समय नहीं है)। और मैं VB.NET कोड के साथ समस्या को दोहरा सकता हूं।
मार्क हर्ड

3

सी # के बारे में वास्तव में कुछ रोमांचक है, जिस तरह से यह बंद संभालती है।

स्टैक वैरिएबल मानों को क्लोजर फ्री वैरिएबल पर कॉपी करने के बजाय, यह करता है कि प्रीप्रोसेसर जादू चर के सभी घटनाओं को एक वस्तु में लपेटता है और इस तरह इसे स्टैक से बाहर ले जाता है - सीधे ढेर पर! :)

मुझे लगता है, कि एमएल से ही C # को और भी अधिक कार्यात्मक रूप से पूर्ण (या लैम्ब्डा-पूर्ण हुह) भाषा बनाता है (जो AFAIK को कॉपी करने वाले स्टैक मान का उपयोग करता है)। F # में वह सुविधा भी है, जैसा C # करता है।

यह मेरे लिए बहुत खुशी लाता है, धन्यवाद एमएस दोस्तों!

हालांकि यह एक विषमता या कोने का मामला नहीं है ... लेकिन स्टैक-आधारित VM भाषा से वास्तव में कुछ अप्रत्याशित है :)


3

एक सवाल से मैंने बहुत पहले नहीं पूछा था:

सशर्त संचालक निहित नहीं कर सकता?

दिया हुआ:

Bool aBoolValue;

जहां aBoolValueया तो सही या गलत सौंपा गया है;

निम्नलिखित संकलन नहीं होगा:

Byte aByteValue = aBoolValue ? 1 : 0;

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

Int anIntValue = aBoolValue ? 1 : 0;

प्रदान किया गया उत्तर बहुत अच्छा है।


हालांकि मुझे ve not test it Iयकीन है कि यह काम करेगा: बाइट aByteValue = aBoolValue? (बाइट) 1: ​​(बाइट) 0; या: बाइट aByteValue = (बाइट) (aBoolValue; 1: 0);
एलेक्स पैकुरर 12

2
हाँ, एलेक्स, यह काम करेगा। निहित कास्टिंग में कुंजी है। 1 : 0अकेले ही int को डाली जाएगी, बाइट को नहीं।
MPelletier

2

ग # में डांटना वास्तव में कई बार विचित्र है। आइए मैं आपको एक उदाहरण देता हूं:

if (true)
{
   OleDbCommand command = SQLServer.CreateCommand();
}

OleDbCommand command = SQLServer.CreateCommand();

यह संकलित करने में विफल रहता है, क्योंकि कमांड पुनर्वितरित होता है? इस तरह से स्टैकओवरफ्लो पर और मेरे ब्लॉग में इस तरह से काम करने के बारे में कुछ इच्छुक अनुमान हैं ।


34
मुझे वह विशेष रूप से विचित्र नहीं लगता। जिसे आप अपने ब्लॉग में "पूरी तरह से सही कोड" कहते हैं, वह भाषा विनिर्देश के अनुसार पूरी तरह से गलत है । यह कुछ काल्पनिक भाषा आप में सही हो सकता है की तरह होने के लिए सी #, लेकिन भाषा कल्पना काफी स्पष्ट है कि सी # में यह अवैध है।
जॉन स्कीट

7
वैसे यह C / C ++ में मान्य है। और चूँकि यह C # है इसलिए मुझे यह पसंद है कि मैं अभी भी काम करूँ। मुझे जो सबसे ज्यादा परेशान करता है वह यह है कि कंपाइलर के ऐसा करने का कोई कारण नहीं है। नेस्टेड स्कूपिंग करना कठिन नहीं है। मुझे लगता है कि यह सब कम से कम सुप्रभात के तत्व के लिए नीचे आता है। मतलब यह हो सकता है कि कल्पना यह और वह कहती है, लेकिन यह वास्तव में मेरी बहुत मदद नहीं करता है अगर यह पूरी तरह से अतार्किक है कि यह इस तरह से व्यवहार करता है।
एंडर्स रुने जेन्सेन

6
C #! = C / C ++। क्या आप भी cout का उपयोग करना चाहेंगे << "हैलो वर्ल्ड!" << एंडल; कंसोल के बजाय। क्राइटलाइन ("हैलो वर्ल्ड!") ;? यह भी अतार्किक नहीं है, बस युक्ति पढ़ें।
क्रेड्स

9
मैं स्कूपिंग नियमों के बारे में बोल रहा हूं जो भाषा के मूल का हिस्सा है। आप मानक पुस्तकालय के बारे में बोल रहे हैं। लेकिन यह अब मेरे लिए स्पष्ट है कि मुझे इसमें प्रोग्रामिंग शुरू करने से पहले बस सी # भाषा के छोटे विनिर्देश को पढ़ना चाहिए।
एंडर्स रूने जेन्सन

6
एरिक लिपर्ट ने वास्तव में उन कारणों को पोस्ट किया है जिनके कारण C # को हाल ही में डिज़ाइन किया गया है: blogs.msdn.com/ericlippert/archive/2009/11/02/… । सारांश यह है कि इसकी संभावना कम है कि परिवर्तनों के अनपेक्षित परिणाम होंगे।
हेलेथ नोव
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.