मैं डिबगिंग के लिए एक बहुत ही प्राथमिक जेनेरिक ऑब्जेक्ट प्रिंटर बनाने की कोशिश कर रहा हूं, जो आपको लिंकपैड में मिलने वाली उत्कृष्टता से प्रेरित है।

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

ILookup में एक गैर-जेनेरिक इंटरफ़ेस नहीं है और यह IDictionary को लागू नहीं करता है, इसलिए मैं इस समय एक तरह से अटका हुआ हूं, क्योंकि मैं यह नहीं कह सकता o as ILookup<object,object>... उस मामले के लिए, मैं मैं जानना चाहता हूं कि किसी सामान्य इंटरफ़ेस में कैसे जाना है...मान लीजिए मैं CustomObject<,,> के लिए एक विशेष मामला रखना चाहता हूं।

void Print(object o)
{
    if(o == null || o.GetType().IsValueType || o is string)
    {
         Console.WriteLine(o ?? "*nil*");
         return;
    }

    var dict = o as IDictionary;     
    if(dict != null)
    {
        foreach(var key in (o as IDictionary).Keys)
        {
            var value = dict[key];
            Print(key + " " + value);
        }
        return;
    }

    //how can i make it work with an ILookup? 
    //????????? 


    var coll = o as IEnumerable;
    if(coll != null)
    {
        foreach(var item in coll)
        { print(item); }
        return;
    }

    //else it's some object, reflect the properties+values
    {
        //reflectiony stuff
    }
}
3
dan 23 फरवरी 2011, 08:21
यह बहुरूपता के साथ भी आसान हो सकता है, अर्थात, void Print(IDictionary dict), void Print(IEnumerable ienum), void Print(object o), आदि।
 – 
mellamokb
23 फरवरी 2011, 08:54
- मैं भी ऐसा सोचा था। हो सकता है कि मैं इसे गलत कर रहा हूं, लेकिन पारस्परिक रूप से पुनरावर्ती Print कॉल वैसा व्यवहार नहीं करते जैसा आप चाहते हैं।
 – 
Kobi
23 फरवरी 2011, 08:57
@xanatos के अनुसार, ILookup, IEnumerable का IEnumerable है। ऐसा लगता है कि आपका वर्तमान कोड इस तरह काम करना चाहिए। यदि आप ILookup प्रकार की किसी वस्तु से गुजरते हैं तो क्या होता है?
 – 
mellamokb
23 फरवरी 2011, 08:57
@ कोबी: मैंने पाया कि इसे ठीक से काम करने के लिए मुझे void Print(string s) भी जोड़ना पड़ा।
 – 
mellamokb
23 फरवरी 2011, 08:57
एक नोट के रूप में, मैंने अपनी प्रतिक्रिया हटा दी क्योंकि यदि कोई ऑब्जेक्ट एक आईलुकअप है तो "खोज" करने का मेरा तरीका गलत था (मैंने केवल लुकअप कार्यान्वयन के लिए जांच की थी)। IEnumerable का IEnumerable सत्य है और काम करता है लेकिन वह "कुंजी" भाग को "खो" देगा। IEnumerable का IEnumerable उसे केवल value part देगा।
 – 
xanatos
23 फरवरी 2011, 09:02

3 जवाब

सबसे बढ़िया उत्तर

मुझे यकीन नहीं है कि आप वास्तव में क्या हासिल करने की कोशिश कर रहे हैं, लेकिन अपने विशिष्ट प्रश्न का उत्तर देने के लिए, आप इस तरह प्रतिबिंब का उपयोग कर सकते हैं:

public static void PrintIfLookup(object obj)
{
    if (obj == null)
        throw new ArgumentNullException("obj");

    // Find first implemented interface that is a constructed version of
    // ILookup<,>, or null if no such interface exists.
    var lookupType = obj
                    .GetType()
                    .GetInterfaces()
                    .FirstOrDefault
                     (i => i.IsGenericType &&
                           i.GetGenericTypeDefinition() == typeof(ILookup<,>));

    if (lookupType != null)
    {
        // It is an ILookup<,>. Invoke the PrintLookup method
        // with the correct type-arguments.

        // Method to invoke is private and static.
        var flags = BindingFlags.NonPublic | BindingFlags.Static;

        // Assuming the containing type is called Foo.
        typeof(Foo).GetMethod("PrintLookup", flags)
                   .MakeGenericMethod(lookupType.GetGenericArguments())
                   .Invoke(null, new[] { obj });
    }

}

private static void PrintLookup<TKey, TElement>(ILookup<TKey, TElement> lookup)
{
    // TODO: Printing logic    
}

मैंने इसे इस तरह से लिखने की कोशिश की है कि आप जेनरिक के साथ प्रिंटिंग लॉजिक को मजबूती से टाइप करके लिख सकें। यदि आप चाहें, तो आप लुकअप में प्रत्येक IGrouping<,> से कुंजी और मान प्राप्त करने के लिए और भी अधिक प्रतिबिंब कर सकते हैं।

संपादित करें: वैसे, यदि आप C# 4 पर हैं, तो आप if कथन के पूरे भाग को इसके साथ बदल सकते हैं:

PrintLookup((dynamic)obj);
4
Ani 23 फरवरी 2011, 09:15

बहुरूपता आपके कोड को थोड़ा सरल बना सकता है।

void Print(IDictionary dict)
{
    foreach (var key in dict.Keys)
    {
        var value = dict[key];
        Print(key + " " + value);
    }
}

void Print(object o)
{
    if (o == null || o.GetType().IsValueType || o is string)
    {
        Console.WriteLine(o ?? "*nil*");
        return;
    }
}

void Print(string s)
{
    Console.WriteLine(s);
}

void Print(IEnumerable ie)
{
    foreach (dynamic obj in ie)
    {
        Print(obj);
    }
}
1
mellamokb 23 फरवरी 2011, 09:01
वह भी मेरी समस्या थी, आपको dynamic का उपयोग करने की आवश्यकता है, जो ईमानदारी से कहूं तो मैं बचना चाहूंगा। असेंबली, आप IDictionary कुंजी/मान, ILookup, आदि पर गतिशील स्वरूपण का उपयोग करना चाहेंगे।
 – 
Kobi
23 फरवरी 2011, 09:09
@ कोबी: क्या वास्तव में dynamic और प्रतिबिंब के बीच कोई अंतर है? वे दोनों प्रकार की जाँच को रनटाइम पर ले जाते हैं, और dynamic इस तरह के विशेष अनुप्रयोगों को व्यक्त करने के लिए अधिक संक्षिप्त हो सकते हैं।
 – 
mellamokb
23 फरवरी 2011, 09:12
आप सही कह रहे हैं, dynamic यहाँ बहुत बेहतर है, यह प्रतिबिंब को बहुत सरल करता है। विशेष रूप से, यह if प्रकारों और कई as/is को हटा देता है, जिनकी मुझे परवाह नहीं है। मैं उम्मीद कर रहा था कि कोई प्रतिबिंब नहीं, और अधिक नहीं :)
 – 
Kobi
23 फरवरी 2011, 09:16

यह निर्धारित करने के लिए कि प्रकार प्रतिबिंब का उपयोग करके कुछ सामान्य इंटरफ़ेस लागू करता है:

var objType = o.GetType();

// get the ILookup<,> interface type (if the type implements it)
var lookupInterface = objType.GetInterface("System.Linq.ILookup`2");

// the type implemented the interface if returned non-null value
var isILookup = lookupInterface != null;

सामान्य प्रकारों के लिए मैंगलिंग नाम का पैटर्न है

type_name`generic_parameter_count

एक सामान्य प्रकार के विशिष्ट उदाहरण के लिए:

type_name`generic_parameter_count[type_name_1,...,type_name_n]

इस मामले में, ILookup<,> के दो पैरामीटर थे, इसलिए यह है:

System.Linq.ILookup`2

हमें सटीक उदाहरण में कोई दिलचस्पी नहीं है इसलिए हमें प्रकार पैरामीटर निर्दिष्ट करने की आवश्यकता नहीं है।

0
Jeff Mercado 23 फरवरी 2011, 08:58
@Ani: हर कोई एक ही बात सोच रहा है ... लेकिन क्या कोई बेहतर समाधान है?
 – 
mellamokb
23 फरवरी 2011, 09:10
@mellamokb: हाँ, वहाँ है। निर्मित जेनेरिक प्रकार पर GetGenericTypeDefinition को कॉल करने की चाल है।
 – 
Ani
23 फरवरी 2011, 09:12
@ एनी: यह इसे कम सुरक्षित या कम कुशल नहीं बनाता है। यदि आप उस प्रकार का सटीक नाम जानते हैं जिसे आप ढूंढ रहे हैं, तो उस प्रकार की खोज आवश्यक नहीं है। यह एक विकल्प है हाँ लेकिन यह दृष्टिकोण उतना ही अच्छा है। अब अपरिचित या जो कुछ भी समझ में आता है, के कारण लोग इस दृष्टिकोण से सहज नहीं हो सकते हैं, लेकिन यह इसे बुरा नहीं बनाता है।
 – 
Jeff Mercado
23 फरवरी 2011, 09:21
@ जेफ: आईएमओ, यह इसे कम सुरक्षित बनाता है। उस नाम के साथ एक अलग इंटरफ़ेस हो सकता है। बीटीडब्ल्यू, मैं मानता हूं कि मैं जो कहता हूं वह सिर्फ मेरी राय है। यह तकनीक अधिक संक्षिप्त है, लेकिन जब अन्य विकल्प उपलब्ध हों तो मैं टाइप-नामों के लिए स्ट्रिंग्स का उपयोग नहीं करना पसंद करता हूं।
 – 
Ani
23 फरवरी 2011, 09:25
@ एनी: अगर मेरे पास यहां पूरी तरह से योग्य नामों का उपयोग नहीं किया जाता है। यहां कोई अस्पष्टता नहीं है इसलिए यह कोई मुद्दा नहीं है।
 – 
Jeff Mercado
23 फरवरी 2011, 09:27