2012-03-29 9 views
9

असल में, मुझे यह पूछना चाहिए: मैं यह कैसे कर सकता हूं और सीएलएस अनुपालन बने रहें? क्योंकि ऐसा करने का एकमात्र तरीका मैं इस प्रकार सोच सकता हूं, लेकिन __makeref, FieldInfo.SetValueDirect या केवल System.TypedReference का उपयोग सामान्य रूप से सीएलएस अनुपालन को अमान्य करता है।क्या मैं बॉक्सिंग के बिना प्रतिबिंब के माध्यम से एक संरचना पर एक मूल्य निर्धारित कर सकता हूं?

// code illustrating the issue: 
TestFields fields = new TestFields { MaxValue = 1234 }; // test struct with one field 

FieldInfo info = fields.GetType().GetField("MaxValue"); // get the FieldInfo 

// actual magic, no boxing, not CLS compliant: 
TypedReference reference = __makeref(fields); 
info.SetValueDirect(reference, 4096); 

SetValueDirect के अनुरूप समकक्ष SetValue है, लेकिन यह लक्ष्य के रूप में एक वस्तु ले जाता है, इसलिए मेरी struct बॉक्सिंग किया जाएगा, मुझे बनाने एक प्रति, नहीं मूल चर पर एक मूल्य की स्थापना।

SetValue के लिए एक सामान्य समकक्ष जहां तक ​​मुझे पता है, अस्तित्व में नहीं है। प्रतिबिंब के माध्यम से एक (संदर्भ के लिए) संरचना के क्षेत्र को स्थापित करने का कोई अन्य तरीका है?

उत्तर

5

SetValueDirect पर cls अनुरूप आवरण करें:

var item = new MyStruct { X = 10 }; 

    item.GetType().GetField("X").SetValueForValueType(ref item, 4); 


[CLSCompliant(true)] 
static class Hlp 
{ 
    public static void SetValueForValueType<T>(this FieldInfo field, ref T item, object value) where T : struct 
    { 
    field.SetValueDirect(__makeref(item), value); 
    } 
} 
+0

शायद मैं CLSCompliancy को समझ नहीं पा रहा हूं, मैंने सोचा था कि इसका मतलब है कि आप _use_ गैर-अनुरूप सुविधाओं को नहीं कर सकते। यदि इसकी अनुमति है, तो यह चीजों को वास्तव में बहुत आसान बनाता है। – Abel

+1

@Abel: सीएलएस अनुपालन का मतलब है कि आपके सार्वजनिक सदस्य केवल सीएलएस-अनुरूप प्रकार का संदर्भ देते हैं। यह आपके सदस्यों में क्या शामिल है इसके बारे में कुछ भी नहीं कहता है। – Gabe

+0

ओह, मेरी टिप्पणी-संपादन खो गया। हां, मैंने देखा, यह सीएलएस अनुपालन पर एमएसडीएन पर शीर्ष तीन गोलियों से स्पष्ट है (http://msdn.microsoft.com/en-us/library/bhc3fa7f.aspx)। फिर भी यह बहुत अजीब लगता है कि मुझे इसे काम करने के लिए एक [अनूदित कीवर्ड __makeref] (http://www.codeproject.com/Articles/38695/UnCommon-C-keywords-A-Look#makref) चाहिए। – Abel

2

यह सुनिश्चित नहीं है कि यह आपकी बाधाओं में फिट होगा, लेकिन संरचना उदाहरण को ValueType, SetValue के रूप में घोषित करके अपेक्षित काम करेगा।

ValueType fields = new TestFields { MaxValue = 1234 }; // test struct with one field 
    FieldInfo info = typeof(TestFields).GetField("MaxValue"); // get the FieldInfo 
    info.SetValue(fields, 4096); 
    Console.WriteLine(((TestFields)fields).MaxValue); // 4096 

कुछ और जानकारी के लिए this answer देखें।

+1

+1: आपका जवाब निश्चित रूप से दिलचस्प है, लेकिन अपने कोड _not_ मूल struct पर काम करता है। इसके बजाय, इसे SetValue के लिए बॉक्स किया गया है और अनबॉक्स किया गया है क्योंकि आपने इसे WriteLine के उपयोग के लिए डाला है। अपने लिए यह देखने के लिए, आईएल की जांच करें। – Abel

+0

मैंने आईएल को नहीं देखा लेकिन मैंने सत्यापित किया कि आखिरी पंक्ति वास्तव में 4096 प्रदर्शित करती है, तो यह मूल उदाहरण पर कैसे काम नहीं कर सकता है? –

+0

ठीक है, अब मैंने आईएल को देखा था। मैं बहुत धाराप्रवाह नहीं हूं लेकिन मैं उस बॉक्स कॉल को देखता हूं जिसके बारे में आप बात कर रहे हैं। स्थानीय अनुभाग से, यह टेस्टफिल्ड्स के दो उदाहरण घोषित कर रहा है जब सी # में केवल एक है। बहुत अजीब। क्या यह वास्तविक मुक्केबाजी है जिसके बारे में आप परवाह है या यह मान सही ढंग से सेट हो जाता है? –

6

गुण के लिए, यदि आप struct और संपत्ति प्रकार है, तो आप संपत्ति सेटर से एक प्रतिनिधि बना सकते हैं। आप का कहना है के रूप में, खेतों setters नहीं है, लेकिन आप एक है कि ठीक उसी बर्ताव करता है बना सकते हैं:

delegate void RefAction<T1, T2>(ref T1 arg1, T2 arg2); 

struct TestFields 
{ 
    public int MaxValue; 

    public int MaxValueProperty 
    { 
     get { return MaxValue; } 
     set { MaxValue = value; } 
    } 
}; 

static class Program 
{ 
    static void Main(string[] args) 
    { 
     var propertyInfo = typeof(TestFields).GetProperty("MaxValueProperty"); 
     var propertySetter = (RefAction<TestFields, int>)Delegate.CreateDelegate(typeof(RefAction<TestFields, int>), propertyInfo.GetSetMethod()); 

     var fieldInfo = typeof(TestFields).GetField("MaxValue"); 

     var dynamicMethod = new DynamicMethod(String.Empty, typeof(void), new Type[] { fieldInfo.ReflectedType.MakeByRefType(), fieldInfo.FieldType }, true); 
     var ilGenerator = dynamicMethod.GetILGenerator(); 
     ilGenerator.Emit(OpCodes.Ldarg_0); 
     ilGenerator.Emit(OpCodes.Ldarg_1); 
     ilGenerator.Emit(OpCodes.Stfld, fieldInfo); 
     ilGenerator.Emit(OpCodes.Ret); 
     var fieldSetter = (RefAction<TestFields, int>)dynamicMethod.CreateDelegate(typeof(RefAction<TestFields, int>)); 

     var fields = new TestFields { MaxValue = 1234 }; 
     propertySetter(ref fields, 5678); 
     fieldSetter(ref fields, 90); 
     Console.WriteLine(fields.MaxValue); 
    } 
} 
+0

हाँ, यह सच है, लेकिन मेरा प्रश्न फ़ील्ड के बारे में है, गुणों के बारे में नहीं। थोड़ा लेकिन महत्वपूर्ण अंतर: फ़ील्ड में समर्पित सेटटर नहीं है। – Abel

+0

ओह, ठीक है, इसके बारे में खेद है, संपादित करेंगे। – hvd

+0

@ एबेल अचानक यह कम सुरुचिपूर्ण लगता है, लेकिन यह अभी भी खेतों के साथ काम करता है। (यदि आप उन्हें बहुत उपयोग करते हैं तो आप बनाई गई विधियों को कैश कर सकते हैं।) – hvd

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

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