2017-11-10 22 views
5

के बीच संदर्भों की तुलना में मुझे बॉक्सिंग और संदर्भ तुलना के बारे में आज वीबीएनईटी में एक व्यवहार का सामना करना पड़ा जिसकी मुझे उम्मीद नहीं थी। उदाहरण के लिए मैंने एक सरल कार्यक्रम लिखा है जो किसी भी प्रकार के चर को निष्क्रिय रूप से अद्यतन करने का प्रयास करता है।ऑब्जेक्ट मुक्केबाजी में अंतर/सी # और वीबी.Net

using System; 

public static class Program 
{ 

    private static object o3; 

    public static void Main() 
    { 
     Console.WriteLine("Hello World"); 

     Test<DateTimeOffset?> value = new Test<DateTimeOffset?>(); 
     Console.WriteLine(value.Value == null); 
     DateTimeOffset dt1 = new DateTimeOffset(2017, 1, 1, 1, 1, 1, TimeSpan.Zero); 
     DateTimeOffset dt2 = new DateTimeOffset(2017, 1, 2, 1, 1, 1, TimeSpan.Zero); 

     Console.WriteLine(value.TrySetValue(null, dt1)); 
     Console.WriteLine(value.Value == dt1); 

     // this should fail 
     Console.WriteLine(value.TrySetValue(null, dt2)); 
     Console.WriteLine(value.Value == dt1); 

     // this should succeed 
     Console.WriteLine(value.TrySetValue(dt1, dt2)); 
    } 
} 

public class Test<T> 
{ 


    public T Value { 
     get { return (T)System.Threading.Volatile.Read(ref _value); } 
    } 


    private object _value; 

    public bool TrySetValue(T oldValue, T newValue) 
    { 
     object curValObj = System.Threading.Volatile.Read(ref _value); 
     if (!object.Equals((T)curValObj, oldValue)) 
      return false; 
     object newValObj = (object)newValue; 
     return object.ReferenceEquals(System.Threading.Interlocked.CompareExchange(ref _value, newValObj, curValObj), curValObj); 
    } 

} 

इस कार्यक्रम का उत्पादन होता है:

यहाँ (https://dotnetfiddle.net/VsMBrg) सी # में एक कार्यक्रम है

Hello World 
True 
True 
True 
False 
True 
True 

यह उम्मीद और सब कुछ ठीक काम करने के लिए लगता है के रूप में है।

Imports System 

Public Module Module1 

    private o3 as object 

    Public Sub Main() 
     Console.WriteLine("Hello World") 

     Dim value As New Test(Of DateTimeOffset?) 
     Console.WriteLine(value.Value is nothing) 
     Dim dt1 As New DateTimeOffset(2017, 1, 1, 1, 1, 1, TimeSpan.Zero) 
     Dim dt2 As New DateTimeOffset(2017, 1, 2, 1, 1, 1, TimeSpan.Zero) 

     Console.WriteLine(value.TrySetValue(Nothing, dt1)) 
     Console.WriteLine(value.Value = dt1) 

     ' This should fail 
     Console.WriteLine(value.TrySetValue(Nothing, dt2)) 
     Console.WriteLine(value.Value = dt1) 

     ' This should succeed 
     Console.WriteLine(value.TrySetValue(dt1, dt2)) 
    End Sub 
End Module 

public class Test(Of T) 


    Public readonly Property Value As T 
     Get 
      Return CType(Threading.Volatile.Read(_value), T) 
     End Get 
    End Property 

    Private _value As Object 

    Public Function TrySetValue(oldValue As T, newValue As T) As Boolean 
     Dim curValObj As Object = Threading.Volatile.Read(_value) 
     If Not Object.Equals(CType(curValObj, T), oldValue) Then Return False 
     Dim newValObj = CObj(newValue) 
     Return Object.ReferenceEquals(Threading.Interlocked.CompareExchange(_value, newValObj, curValObj), curValObj) 
    End Function 

end class 

यहाँ आउटपुट है:

Hello World 
True 
True 
True 
False 
True 
False 

यहाँ पिछले बयान जिसका अर्थ है कि सेट काम नहीं किया गलत है यहाँ VB.NET (https://dotnetfiddle.net/lasxT2) में एक ही कार्यक्रम है। क्या मैं यहां कुछ गलत कर रहा हूं या वीबी.नेट में समस्या है?

(नोट:, पर ध्यान न दें/लिखते हैं वाष्पशील पढ़ता इस उदाहरण कोई सूत्र तो यह सूत्रण से प्रभावित नहीं है है): अगर मैं बदल पूर्णांक टी तो सब कुछ ठीक काम करता है:


संपादित
(dotnetfiddle.net/X6uLZs)। इसके अलावा, अगर मैं एक कस्टम वर्ग के लिए टी बदल यह भी ठीक काम करता है:
dotnetfiddle.net/LnOOme

उत्तर

4

मेरा मानना ​​है कि इस मुद्दे का कारण वास्तव में वीबी के Object हैंडलिंग, जहां कुछ स्थानों में इसे और अधिक सी # के लिए इसी तरह की है सादा Object से dynamic। विशेष रूप से, अगर मैं फिर से लिखें TrySetValue के रूप में:

Public Function TrySetValue(oldValue As T, newValue As T) As Boolean 
    Dim curValObj As Object = _value 'Threading.Volatile.Read(_value) 
    Console.Write(Object.ReferenceEquals(curValObj,_value)) 
    If Not Object.Equals(CType(curValObj, T), oldValue) Then Return False 
    Dim newValObj = CObj(newValue) 
    Return Object.ReferenceEquals(Threading.Interlocked.CompareExchange(_value, newValObj, curValObj), curValObj) 
    End Function 

हम उम्मीद करते हैं कभी नहीं होगा कि Console.WriteLineFalse मुद्रित करने के लिए। लेकिन यह वही है जो यह करता है। इस कोड को सी # (प्रतिबिंबक का उपयोग करके) पर वापस लेना, मुझे यह कोड प्राप्त होता है:

public bool TrySetValue(T oldValue, T newValue) 
{ 
    object objectValue = RuntimeHelpers.GetObjectValue(this._value); 
    Console.Write(object.ReferenceEquals(RuntimeHelpers.GetObjectValue(objectValue), RuntimeHelpers.GetObjectValue(this._value))); 
    if (!object.Equals(Conversions.ToGenericParameter<T>(objectValue), oldValue)) 
    { 
     return false; 
    } 
    object obj3 = newValue; 
    return object.ReferenceEquals(RuntimeHelpers.GetObjectValue(Interlocked.CompareExchange(ref this._value, RuntimeHelpers.GetObjectValue(obj3), RuntimeHelpers.GetObjectValue(objectValue))), RuntimeHelpers.GetObjectValue(objectValue)); 
} 

ओह प्रिय। GetObjectValue पर उन सभी कॉल क्या हैं? खैर, प्रभाव वे प्रतियां बॉक्स किए गए मान प्रकारों से बने होने का कारण बन रहे हैं और इसलिए curValObj में _value के समान ऑब्जेक्ट का वास्तविक संदर्भ कभी नहीं होता है, और इसलिए Interlocked.CompareExchange जब हम साथ काम कर रहे हों तो कभी भी काम नहीं कर सकता वास्तविक वस्तु संदर्भ।

मैं इस कोड को फिर से लिखने का एक अच्छा तरीका नहीं सोच सकता, वर्तमान में, जो आप चाहते हैं उसे करने के लिए। और शायद हम एक आगे कारण देख सकते हैं क्यों CompareExchange की Object अधिभार हमें चेतावनी देते हैं:

मूल्य प्रकार के साथ इस अधिभार प्रयोग न करें।

+0

आईएल को देखते हुए, सी # निर्देश 'unbox.any' है जहां वीबी निर्देश' रूपांतरण है।ToGeneric पैरामीटर '। तो इसका मतलब है कि वीबी संरचना की एक प्रति वापस कर रहा है लेकिन सी # एक ही संरचना का संदर्भ दे रहा है, सही? – Crowcoder

+0

@ क्रोकोडर - इस छोटे कोड नमूने में अप्रत्याशित प्रतियों की कतरनी संख्या ने मुझे सवाल किया है कि कोई भी वीबी कोड बिल्कुल कैसे काम करता है :-( –

+0

सीएलआर स्रोत कोड से: "तकनीकी रूप से हम उन्हें कॉपी किए बिना बॉक्स किए गए डेटटाइम और डेसिमल वापस कर सकते हैं यहां, लेकिन वीबी को एहसास हुआ कि यह उनके ग्राहकों के लिए एक तोड़ने वाला बदलाव होगा। इसलिए उन्हें कॉपी करें। " –

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