2012-01-30 25 views
49

का उपयोग करके घोषणा के क्रम में गुण प्राप्त करें मुझे कक्षा में घोषित क्रम में प्रतिबिंब का उपयोग करके सभी गुणों को प्राप्त करने की आवश्यकता है। MSDN के अनुसार, जब GetProperties()प्रतिबिंब

GetProperties पद्धति का उपयोग करके इस तरह के वर्णमाला या घोषणा आदेश के रूप में एक विशेष क्रम में गुण, वापस नहीं करता है आदेश की गारंटी नहीं किया जा सकता।

लेकिन मैंने पढ़ा है कि MetadataToken द्वारा गुणों का ऑर्डर करके एक कार्यवाही है। तो मेरा सवाल है, क्या यह सुरक्षित है? मुझे इसके बारे में एमएसडीएन पर कोई जानकारी नहीं मिल रही है। या इस समस्या को हल करने का कोई और तरीका है?

मेरे वर्तमान कार्यान्वयन इस प्रकार दिखता है:

var props = typeof(T) 
    .GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) 
    .OrderBy(x => x.MetadataToken); 
+12

वैसे भी, यह बुरा विचार है। ऑर्डर वैल्यू या किसी अन्य मेटाडेटा के साथ अपनी खुद की विशेषता बनाएं और उस विशेषता के साथ कक्षा के फ़ील्ड चिह्नित करें। –

+1

आप शायद एक नई विशेषता जोड़ सकते हैं जिसमें ऑर्डर का एक int शामिल है। फिर गुण प्राप्त करें, प्रत्येक प्रॉपर्टी के DisplayOrderAttribute प्राप्त करें और उसमें सॉर्ट करें? – BlueChippy

+1

जिज्ञासा से, आप यह क्यों कर रहे हैं, आप क्या हासिल करने की कोशिश कर रहे हैं? –

उत्तर

12

MSDNMetadataToken के अनुसार एक मॉड्यूल के अंदर अद्वितीय है - कुछ भी नहीं कह रही है कि यह बिल्कुल किसी भी क्रम की गारंटी देता है है।

यदि भी यह उस तरीके से व्यवहार करता है जिस पर आप इसे चाहते हैं तो कार्यान्वयन-विशिष्ट होगा और बिना किसी सूचना के बदल सकता है।

यह पुराना MSDN blog entry देखें।

मैं इस तरह के कार्यान्वयन विवरण पर किसी भी निर्भरता से दूर रहने की दृढ़ता से अनुशंसा करता हूं - this answer from Marc Gravell देखें।

यदि आपको संकलन समय पर कुछ चाहिए तो आप Roslyn पर देख सकते हैं (हालांकि यह बहुत शुरुआती चरण में है)।

9

यदि आप विशेषता मार्ग पर जा रहे हैं, तो यहां एक विधि है जिसका मैंने अतीत में उपयोग किया है;

public static IOrderedEnumerable<PropertyInfo> GetSortedProperties<T>() 
{ 
    return typeof(T) 
    .GetProperties() 
    .OrderBy(p => ((Order)p.GetCustomAttributes(typeof(Order), false)[0]).Order); 
} 

फिर इसे इस तरह उपयोग करें;

var test = new TestRecord { A = 1, B = 2, C = 3 }; 

foreach (var prop in GetSortedProperties<TestRecord>()) 
{ 
    Console.WriteLine(prop.GetValue(test, null)); 
} 

कहां;

class TestRecord 
{ 
    [Order(1)] 
    public int A { get; set; } 

    [Order(2)] 
    public int B { get; set; } 

    [Order(3)] 
    public int C { get; set; } 
} 

अगर आप अपने गुण स्पष्ट रूप से सभी पर तुलनीय गुण के बिना एक प्रकार पर चला विधि barf होगा, इसलिए सावधान उसके उपयोग के तरीके हो सकता है और यह आवश्यकता के लिए पर्याप्त होना चाहिए।

मैंने ऑर्डर की परिभाषा छोड़ दी है: विशेषता है क्योंकि मार्क ग्रेवेल के पोस्ट के याहिया के लिंक में एक अच्छा नमूना है।

+2

यदि यह एक प्रदर्शन आवश्यकता है, तो [DataAnnotations.DisplayAttribute] का उपयोग करना उचित होगा (http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations .displayattribute.aspx), जिसमें ऑर्डर फ़ील्ड है। – Jerph

0

आप अतिरिक्त निर्भरता के साथ खुश हैं, मार्क Gravell के Protobuf-Net प्रतिबिंब और कैशिंग आदि लागू करने के लिए बस [ProtoMember] का उपयोग कर अपने खेतों को सजाने के लिए सबसे अच्छा तरीका के बारे में चिंता है और फिर संख्यात्मक में क्षेत्रों तक पहुँचने के लिए बिना यह करने के लिए इस्तेमाल किया जा सकता आदेश का उपयोग कर:

MetaType metaData = ProtoBuf.Meta.RuntimeTypeModel.Default[typeof(YourTypeName)]; 

metaData.GetFields(); 
98

ऑन .net 4 पर।5 (and even .net 4.0 in vs2012) आप [CallerLineNumber] विशेषता के साथ चतुर चाल का उपयोग बहुत प्रतिबिंब के साथ बेहतर कर सकते हैं, आप के लिए अपने गुण में दे संकलक डालने आदेश:

[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)] 
public sealed class OrderAttribute : Attribute 
{ 
    private readonly int order_; 
    public OrderAttribute([CallerLineNumber]int order = 0) 
    { 
     order_ = order; 
    } 

    public int Order { get { return order_; } } 
} 


public class Test 
{ 
    //This sets order_ field to current line number 
    [Order] 
    public int Property2 { get; set; } 

    //This sets order_ field to current line number 
    [Order] 
    public int Property1 { get; set; } 
} 

और फिर प्रतिबिंब का उपयोग करें:

var properties = from property in typeof(Test).GetProperties() 
       where Attribute.IsDefined(property, typeof(OrderAttribute)) 
       orderby ((OrderAttribute)property.GetCustomAttributes(typeof(OrderAttribute), false).Single()).Order 
       select property; 

foreach (var property in properties) 
{ 

} 

आप निपटने के लिए है, तो आंशिक कक्षाओं के साथ, आप [CallerFilePath] का उपयोग कर गुणों को सॉर्ट कर सकते हैं।

+0

दिलचस्प, धन्यवाद! – Magnus

+0

वास्तव में एक बेहतर तरीका, धन्यवाद! – Gerard

+2

यह वास्तव में बहुत चालाक है! मुझे आश्चर्य है कि इसके खिलाफ कोई काउंटर तर्क है या नहीं? वास्तव में मेरे लिए काफी सुंदर लग रहा है। मैं Linq2CSV का उपयोग कर रहा हूं और मुझे लगता है कि मैं 'CsvColumnAttribute 'से प्राप्त करूंगा और इसे डिफ़ॉल्ट' फील्ड इंडेक्स 'मान – julealgon

3

मैंने मेटाडाटा टोकन कार्यों द्वारा सॉर्ट करने का परीक्षण किया है।

कुछ उपयोगकर्ताओं का दावा है कि यह किसी भी तरह से अच्छा दृष्टिकोण नहीं है/भरोसेमंद नहीं है, लेकिन मैंने अभी तक इसका कोई सबूत नहीं देखा है - शायद आप यहां कुछ कोड स्निपेट पोस्ट कर सकते हैं जब दृष्टिकोण काम नहीं करता है?

पीछे की संगतता के बारे में - जबकि आप अब अपने .NET 4/.NET 4.5 पर काम कर रहे हैं - माइक्रोसॉफ्ट 5 या उच्चतर नेट बना रहा है, इसलिए आप बहुत अधिक अनुमान लगा सकते हैं कि इस सॉर्टिंग विधि को भविष्य में तोड़ा नहीं जाएगा ।

बेशक शायद 2017 तक जब आप .NET9 में अपग्रेड कर रहे हों तो आप संगतता ब्रेक मार देंगे, लेकिन उस समय तक माइक्रोसॉफ्ट के लोग "आधिकारिक सॉर्ट तंत्र" का पता लगाएंगे। वापस जाने या चीजों को तोड़ने का अर्थ नहीं है।

संपत्ति आदेश के लिए अतिरिक्त विशेषताओं के साथ खेलना समय और कार्यान्वयन भी लेता है - अगर मेटाडाटा टोकन सॉर्टिंग काम करता है तो परेशान क्यों करें?

1

आप कस्टम विशेषता के बजाय System.Component.DataAnnotations में DisplayAttribute का उपयोग कर सकते हैं। वैसे भी आपकी आवश्यकता को प्रदर्शन के साथ कुछ करना है।