अनाम प्रकारों को मापदंडों के रूप में कैसे पारित किया जाए?


143

मैं अन्य कार्यों के लिए अनाम प्रकारों को पैरामीटर के रूप में कैसे पास कर सकता हूं? इस उदाहरण पर विचार करें:

var query = from employee in employees select new { Name = employee.Name, Id = employee.Id };
LogEmployees(query);

यहाँ चर queryमें मजबूत प्रकार नहीं है। मुझे LogEmployeesइसे स्वीकार करने के लिए अपने फ़ंक्शन को कैसे परिभाषित करना चाहिए ?

public void LogEmployees (? list)
{
    foreach (? item in list)
    {

    }
}

दूसरे शब्दों में, मुझे ?निशान के बजाय क्या उपयोग करना चाहिए ।


1
बेहतर अलग डुप्लिकेट प्रश्न जो डेटा लौटने के बजाय पासिंग मापदंडों से संबंधित है
रॉब चर्च

जवाबों:


183

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

public void LogEmployees (IEnumerable<dynamic> list)
{
    foreach (dynamic item in list)
    {
        string name = item.Name;
        int id = item.Id;
    }
}

ध्यान दें कि यह दृढ़ता से टाइप नहीं किया गया है, इसलिए यदि, उदाहरण के लिए, नाम EmployeeName में बदल जाता है, तो आपको पता नहीं चलेगा कि रनटाइम के दौरान कोई समस्या है।


मैंने इसे सही उत्तर के रूप में, dynamicउपयोग के कारण जाँच लिया । मैं असली मेरे लिए काम आया। धन्यवाद :)
सईद नेमाटी

1
मैं मानता हूं कि एक बार डेटा के आसपास से गुजरना शुरू हो जाता है, तो बग्स को खोजने के लिए कठिन परिचय नहीं करने के लिए एक अधिक संरचित तरीका हो सकता है / आमतौर पर पसंद किया जाना चाहिए (आप टाइप सिस्टम को साइडस्टेपिंग कर रहे हैं)। हालाँकि, यदि आप एक समझौता खोजना चाहते हैं, तो एक अन्य तरीका यह है कि आप केवल एक सामान्य शब्दकोश पारित करें। सी # डिक्शनरी इनिशियलाइज़र इन दिनों उपयोग करने के लिए बहुत सुविधाजनक हैं।
जोनास

कुछ मामले हैं जहां आप एक सामान्य कार्यान्वयन चाहते हैं, और कठिन प्रकार पास करने का मतलब संभवतः स्विचिंग या कारखाना कार्यान्वयन है जो कोड को ब्लोट करना शुरू कर देता है। यदि आपके पास वास्तव में गतिशील स्थिति है और आपके द्वारा प्राप्त किए जा रहे डेटा से निपटने के लिए थोड़ा प्रतिबिंब नहीं है, तो यह एकदम सही है। उत्तर के लिए धन्यवाद @ टिम एस
लैरी स्मिथ

42

आप इसे इस तरह से कर सकते हैं:

public void LogEmployees<T>(List<T> list) // Or IEnumerable<T> list
{
    foreach (T item in list)
    {

    }
}

... लेकिन आपको प्रत्येक आइटम के साथ बहुत कुछ करने को नहीं मिलेगा। आप ToString को कॉल कर सकते हैं, लेकिन आप ( सीधे ) Nameऔर Idसीधे उपयोग नहीं कर पाएंगे ।


2
सिवाय आप where T : some typeप्रकार को संकीर्ण करने के लिए पहली पंक्ति के अंत में उपयोग कर सकते हैं । उस बिंदु पर, हालांकि, एक निश्चित प्रकार के सामान्य इंटरफ़ेस की अपेक्षा करने से इंटरफ़ेस की अपेक्षा करना अधिक समझ में आता है। :)
CassOnMars

9
@d_r_w: आप where T : some typeगुमनाम प्रकारों के साथ उपयोग नहीं कर सकते , क्योंकि वे किसी भी प्रकार के इंटरफ़ेस को लागू नहीं करते हैं ...
जॉन स्कीट

@ एलेव: आप ऐसा नहीं कर सकते हैं, फोरचेक के लिए यह आवश्यक है कि वेरिएबल गेट इन्नूमरेटर पर लागू हो और अनाम प्रकार इसकी गारंटी न दें।
CassOnMars

1
@ जोंन स्कीट: अच्छी बात है, आज सुबह मेरा दिमाग कमज़ोर है।
CassOnMars

1
@JonSkeet। मुझे लगता है कि आप प्रतिबिंब का उपयोग कर सकते हैं तब भी गुणों को एक्सेस / सेट कर सकते हैं यदि T एक अनाम प्रकार सही है? मैं एक ऐसे मामले के बारे में सोच रहा हूं, जहां कोई व्यक्ति "सेलेक्ट *" स्टेटमेंट लिखता है और एक गुमनाम (या परिभाषित) वर्ग का उपयोग करता है, जो यह परिभाषित करने के लिए कि आपके अनाम ऑब्जेक्ट पर समान नाम वाले गुणों के लिए क्वेरी परिणाम मैप में कौन से कॉलम हैं।
सी। टिवेल्ट

19

दुर्भाग्य से, आप जो करने की कोशिश कर रहे हैं वह असंभव है। हुड के तहत, क्वेरी चर IEnumerableएक गुमनाम प्रकार का होने के लिए टाइप किया गया है । अनाम प्रकार के नामों को उपयोगकर्ता कोड में प्रस्तुत नहीं किया जा सकता है, इसलिए उन्हें किसी फ़ंक्शन के लिए इनपुट पैरामीटर बनाने का कोई तरीका नहीं है।

आपकी सबसे अच्छी शर्त यह है कि आप एक प्रकार बनाएं और उपयोग करें कि क्वेरी से वापसी के रूप में और फिर इसे फ़ंक्शन में पास करें। उदाहरण के लिए,

struct Data {
  public string ColumnName; 
}

var query = (from name in some.Table
            select new Data { ColumnName = name });
MethodOp(query);
...
MethodOp(IEnumerable<Data> enumerable);

इस मामले में, आप केवल एक क्षेत्र का चयन कर रहे हैं, इसलिए सीधे क्षेत्र का चयन करना आसान हो सकता है। इससे क्वेरी को IEnumerableफ़ील्ड प्रकार के रूप में टाइप किया जाएगा । इस स्थिति में, स्तंभ नाम।

var query = (from name in some.Table select name);  // IEnumerable<string>

मेरा उदाहरण एक था, लेकिन ज्यादातर समय यह अधिक है। कार्यों के माध्यम से आपका जवाब (और अब काफी स्पष्ट है)। मुझे सिर्फ यह सोचने के लिए दोपहर के भोजन के लिए एक ब्रेक की आवश्यकता थी
;;


एक चेतावनी यह है कि जब आप एक उचित वर्ग Equalsपरिवर्तन व्यवहार बनाते हैं। यानी आपको इसे लागू करना होगा। (मैं इस विसंगति के बारे में जानता था, लेकिन फिर भी एक
परावर्तन के

11

जब तक कि पैरामीटर प्रकार नहीं है, आप एक गैर-जेनेरिक फ़ंक्शन में एक अनाम प्रकार पारित नहीं कर सकते object

public void LogEmployees (object obj)
{
    var list = obj as IEnumerable(); 
    if (list == null)
       return;

    foreach (var item in list)
    {

    }
}

अनाम प्रकार एक विधि के भीतर अल्पकालिक उपयोग के लिए अभिप्रेत है।

MSDN से - अनाम प्रकार :

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

(जोर मेरा)


अपडेट करें

आप जो चाहते हैं उसे प्राप्त करने के लिए आप जेनरिक का उपयोग कर सकते हैं:

public void LogEmployees<T>(IEnumerable<T> list)
{
    foreach (T item in list)
    {

    }
}

4
यदि आप विधियों में अनाम प्रकार (या अनाम प्रकार के संग्रह) को पास नहीं कर सकते हैं, तो पूरा LINQ विफल हो जाएगा। आप कर सकते हैं, यह सिर्फ यह है कि यह विधि पूरी तरह से सामान्य होनी चाहिए, गुमनाम प्रकार के गुणों का उपयोग नहीं करना चाहिए।
जॉन स्कीट

2
फिर object- या dynamic, पी
मार्क Gravell

अगर "के रूप में" के साथ कास्टिंग आप की जाँच करनी चाहिए अगर सूची शून्य है
एलेक्स

"कर सकते हैं! =" है "। उपयोग करना objectमेरे उत्तर के अनुसार, अनाम प्रकार में एक विधि को सामान्य बनाने के समान नहीं है।
जॉन स्कीट

8

उदाहरण के लिए, सामान्य तौर पर, आप जेनरिक के साथ ऐसा करते हैं:

MapEntToObj<T>(IQueryable<T> query) {...}

कंपाइलर को तब Tकॉल करना चाहिए जब आप कॉल करते हैं MapEntToObj(query)। बिल्कुल निश्चित नहीं है कि आप विधि के अंदर क्या करना चाहते हैं, इसलिए मैं यह नहीं बता सकता कि क्या यह उपयोगी है ... समस्या यह है कि आपके अंदर MapEntToObjअभी भी नाम नहीं है T- आप या तो कर सकते हैं:

  • के साथ अन्य सामान्य तरीकों को बुलाओ T
  • Tचीजों को करने के लिए प्रतिबिंब का उपयोग करें

लेकिन इसके अलावा, अनाम प्रकारों में हेरफेर करना काफी कठिन है - कम से कम नहीं क्योंकि वे अपरिवर्तनीय हैं; - पी

एक और ट्रिक ( डेटा निकालते समय ) एक चयनकर्ता को भी पास करना है - यानी कुछ ऐसा:

Foo<TSource, TValue>(IEnumerable<TSource> source,
        Func<TSource,string> name) {
    foreach(TSource item in source) Console.WriteLine(name(item));
}
...
Foo(query, x=>x.Title);

1
कुछ नया सीखा है, पता नहीं है कि अनाम प्रकार अपरिवर्तनीय हैं! ;)
एनी लगंग

1
@AnneLagang जो वास्तव में संकलक तक है, क्योंकि यह उन्हें उत्पन्न करता है। VB.NET में, एनॉन-प्रकारों को परस्पर जोड़ा जा सकता है।
मार्क ग्रेवेल


7

आप निम्न चाल के साथ जेनरिक का उपयोग कर सकते हैं (गुमनाम प्रकार तक कास्टिंग):

public void LogEmployees<T>(IEnumerable<T> list)
{
    foreach (T item in list)
    {
        var typedItem = Cast(item, new { Name = "", Id = 0 });
        // now you can use typedItem.Name, etc.
    }
}

static T Cast<T>(object obj, T type)
{
    return (T)obj;
}

6

"गतिशील" का उपयोग इस उद्देश्य के लिए भी किया जा सकता है।

var anonymousType = new { Id = 1, Name = "A" };

var anonymousTypes = new[] { new { Id = 1, Name = "A" }, new { Id = 2, Name = "B" };

private void DisplayAnonymousType(dynamic anonymousType)
{
}

private void DisplayAnonymousTypes(IEnumerable<dynamic> anonymousTypes)
{
   foreach (var info in anonymousTypes)
   {

   }
}

1
यह सही जवाब है! इसे बस और अधिक प्यार की आवश्यकता है :)
कोरेम

2

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

  1. var dynamicResult = anonymousQueryResult.ToList<dynamic>();
  2. विधि हस्ताक्षर: DoSomething(List<dynamic> _dynamicResult)
  3. कॉल विधि: DoSomething(dynamicResult);
  4. किया हुआ।

पेटार इवानोव के लिए धन्यवाद !


0

यदि आप जानते हैं, कि आपके परिणाम एक निश्चित इंटरफ़ेस को लागू करते हैं, तो आप इंटरफ़ेस को डेटाटाइप के रूप में उपयोग कर सकते हैं:

public void LogEmployees<T>(IEnumerable<T> list)
{
    foreach (T item in list)
    {

    }
}

0

मैं IEnumerable<object>तर्क के लिए टाइप का उपयोग करूंगा । हालांकि अपरिहार्य स्पष्ट कलाकारों के लिए एक महान लाभ नहीं है। चियर्स

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.