क्या अनाम वर्ग इंटरफ़ेस लागू कर सकता है?


462

क्या एक गुमनाम प्रकार का इंटरफ़ेस लागू करना संभव है?

मुझे एक कोड मिला है जिसे मैं काम करना चाहूंगा, लेकिन यह नहीं पता कि यह कैसे करना है।

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

public interface DummyInterface
{
    string A { get; }
    string B { get; }
}

public class DummySource
{
    public string A { get; set; }
    public string C { get; set; }
    public string D { get; set; }
}

public class Test
{
    public void WillThisWork()
    {
        var source = new DummySource[0];
        var values = from value in source
                     select new
                     {
                         A = value.A,
                         B = value.C + "_" + value.D
                     };

        DoSomethingWithDummyInterface(values);

    }

    public void DoSomethingWithDummyInterface(IEnumerable<DummyInterface> values)
    {
        foreach (var value in values)
        {
            Console.WriteLine("A = '{0}', B = '{1}'", value.A, value.B);
        }
    }
}

मुझे एक लेख डायनामिक इंटरफ़ेस रैपिंग मिला है जो एक दृष्टिकोण का वर्णन करता है। क्या यह ऐसा करने का सबसे अच्छा तरीका है?


1
लिंक पुराना हो गया है, यह शायद एक उपयुक्त वैकल्पिक liensberger.it/web/blog/?p=298 है
फिल कूपर

1
हां, आप .NET 4 और उच्चतर (DLR के माध्यम से), ImpromptuInterface नुगेट पैकेज का उपयोग करके ऐसा कर सकते हैं ।
ब्रेनस्ल्गस83

1
@PhilCooper आपका लिंक कम से कम 2016 से था - लेकिन सौभाग्य से यह तब से पहले संग्रहीत किया गया था। web.archive.org/web/20111105150920/http://www.liensberger.it/…
पॉल

जवाबों:


360

नहीं, अनाम प्रकार इंटरफ़ेस लागू नहीं कर सकते। से सी # प्रोग्रामिंग गाइड :

अनाम प्रकार वर्ग प्रकार होते हैं जिनमें एक या अधिक सार्वजनिक रीड-ओनली गुण होते हैं। किसी अन्य प्रकार के वर्ग के सदस्यों जैसे कि विधियों या घटनाओं की अनुमति नहीं है। एक अनाम प्रकार को किसी भी इंटरफ़ेस या ऑब्जेक्ट के अलावा टाइप नहीं किया जा सकता है।


5
वैसे भी इस सामान के लिए अच्छा होगा। यदि आप कोड पठनीयता की बात कर रहे हैं, तो लैम्ब्डा अभिव्यक्ति आमतौर पर जाने का तरीका नहीं है। अगर हम RAD की बात कर रहे हैं, तो मैं सभी जावा-जैसे अनाम इंटरफ़ेस कार्यान्वयन में हूँ। वैसे, कुछ मामलों में यह सुविधा प्रतिनिधियों की तुलना में अधिक शक्तिशाली है
आर्सेन ज़ाहरे

18
@ArsenZahray: लंबोदर भाव, जब अच्छी तरह से उपयोग किया जाता है, तो वास्तव में कोड पठनीयता में वृद्धि होती है। वे कार्यात्मक श्रृंखलाओं में उपयोग किए जाने पर विशेष रूप से शक्तिशाली होते हैं, जो स्थानीय चर की आवश्यकता को कम या समाप्त कर सकते हैं।
रॉय टिंकर

2
आप इस तरह से ट्रिक कर सकते हैं "बेनामी इम्प्लीमेंटेशन क्लासेस - ए डिज़ाइन पैटर्न फॉर सी #" - ट्विडोआडेस्टुडिओडब्लॉएस
दिमित्री पावलोव

3
@DmitryPavlov, जो आश्चर्यजनक रूप से मूल्यवान था। राहगीर: यहाँ गाढ़ा संस्करण है।
18

1
आप गुमनाम फ़ील्ड में उसी फ़ील्ड के साथ एक अनाम ऑब्जेक्ट पर जा सकते हैं stackoverflow.com/questions/1409734/cast-to-anonymous-type
Zinov

89

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

2008 में वापस मैं अपने तत्कालीन नियोक्ता के लिए एक कस्टम LINQ प्रदाता लिख ​​रहा था, और एक बिंदु पर मुझे अन्य अनाम लोगों से "मेरे" अनाम वर्गों को बताने में सक्षम होने की आवश्यकता थी, जिसका मतलब था कि उन्हें एक इंटरफ़ेस लागू करना जो मैं टाइप चेक का उपयोग कर सकता था उन्हें। जिस तरह से हमने इसे हल किया वह पहलुओं (हमने PostSharp का उपयोग करके ) था, IL में सीधे इंटरफ़ेस कार्यान्वयन को जोड़ने के लिए। इसलिए, वास्तव में, अनाम कक्षाओं को इंटरफेस लागू करने देना उचित है , आपको वहां पहुंचने के लिए बस नियमों को थोड़ा मोड़ने की जरूरत है।


8
@Gusdor, इस मामले में, बिल्ड पर हमारा पूर्ण नियंत्रण था, और यह हमेशा एक समर्पित मशीन पर चलाया जाता था। इसके अलावा, जब से हम PostSharp का उपयोग कर रहे थे, और हम जो कर रहे थे, उस ढांचे के भीतर पूरी तरह से कानूनी था, कुछ भी वास्तव में पॉप नहीं हो सकता था जब तक कि हमने सुनिश्चित नहीं किया था कि PostSharp हमारे द्वारा उपयोग किए जा रहे बिल्ड सर्वर पर स्थापित किया गया था।
मिया क्लार्क

16
@Gusdor मैं मानता हूं कि अन्य प्रोग्रामर के लिए प्रोजेक्ट को प्राप्त करना और बड़ी मात्रा में कठिनाई के बिना संकलित करना आसान होना चाहिए, लेकिन यह एक अलग मुद्दा है जो अलग-अलग संबोधित किया जा सकता है, बिना टार्चरिंग या फ्रेमवर्क जैसे पोस्टशेयर से पूरी तरह से बचने के लिए। वही तर्क जो आप वीएस या किसी अन्य गैर-मानक एमएस ढांचे के खिलाफ कर सकते हैं, जो सी # कल्पना का हिस्सा नहीं हैं। आपको उन चीजों की आवश्यकता है या फिर यह "पॉप जाता है"। यह एक समस्या नहीं है IMO। समस्या तब होती है जब निर्माण इतना जटिल हो जाता है कि उन चीजों को ठीक से काम करना मुश्किल हो जाता है।
एरॉनएलएस

6
@ZainRizvi नहीं, यह नहीं था। जहाँ तक मुझे पता है, यह अभी भी उत्पादन में है। यह चिंता मुझे तब अजीब लगी, और अब मेरे लिए सबसे अच्छा है। यह मूल रूप से कह रहा था "एक ढांचे का उपयोग न करें, चीजें टूट जाएंगी!"। उन्होंने नहीं किया, कुछ भी नहीं चला, और मुझे आश्चर्य नहीं हुआ।
मिया क्लार्क

3
यह अब बहुत आसान है; कोड उत्पन्न होने के बाद IL को संशोधित करने की कोई आवश्यकता नहीं है; बस ImpromptuInterface का उपयोग करें । - यह आपको किसी भी इंटरफ़ेस से किसी भी ऑब्जेक्ट (अनाम रूप से टाइप की गई वस्तुओं सहित) को बाँधने की अनुमति देता है (यदि आप इंटरफ़ेस के एक हिस्से का उपयोग करने का प्रयास करते हैं, तो क्लास में वास्तव में समर्थन नहीं होता है)।
BrainSlugs83

44

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

इसके आसपास का सबसे अच्छा समाधान कुछ प्रकार के गतिशील प्रॉक्सी है जो आपके लिए कार्यान्वयन बनाता है। उत्कृष्ट LinFu परियोजना का उपयोग करके आप प्रतिस्थापित कर सकते हैं

select new
{
  A = value.A,
  B = value.C + "_" + value.D
};

साथ में

 select new DynamicObject(new
 {
   A = value.A,
   B = value.C + "_" + value.D
 }).CreateDuck<DummyInterface>();

17
Impromptu- इंटरफ़ेस प्रोजेक्ट .NET 4.0 में DLR का उपयोग करके ऐसा करेगा और हल्का वजन है और फिर Linfu है।
jbtule

है DynamicObjectएक LinFu प्रकार? System.Dynamic.DynamicObjectकेवल एक संरक्षित निर्माता है (कम से कम .NET 4.5 में)।
jdmcnair

हाँ। मैं LinFu कार्यान्वयन का उल्लेख कर रहा था, DynamicObjectजो DLR संस्करण से पहले था
Arne Claassen

14

बेनामी प्रकार एक गतिशील प्रॉक्सी के माध्यम से इंटरफेस को लागू कर सकते हैं।

मैंने इस परिदृश्य का समर्थन करने के लिए GitHub पर एक विस्तार विधि और एक ब्लॉग पोस्ट http://wblo.gs/feE लिखा ।

विधि का उपयोग इस तरह किया जा सकता है:

class Program
{
    static void Main(string[] args)
    {
        var developer = new { Name = "Jason Bowers" };

        PrintDeveloperName(developer.DuckCast<IDeveloper>());

        Console.ReadKey();
    }

    private static void PrintDeveloperName(IDeveloper developer)
    {
        Console.WriteLine(developer.Name);
    }
}

public interface IDeveloper
{
    string Name { get; }
}

13

नहीं; एक गुमनाम प्रकार कुछ गुणों को छोड़कर कुछ भी करने के लिए नहीं बनाया जा सकता है। आपको अपना स्वयं का प्रकार बनाने की आवश्यकता होगी। मैंने लिंक किए गए लेख को गहराई से नहीं पढ़ा, लेकिन ऐसा लगता है कि यह रिफ्लेक्शन का उपयोग करता है। मक्खी पर नए प्रकार बनाने के लिए स्वीकार करें; लेकिन अगर आप सी # के भीतर चर्चा को सीमित करते हैं तो आप वही नहीं कर सकते जो आप चाहते हैं।


और ध्यान दें: गुणों में फ़ंक्शंस या voids (एक्शन) भी शामिल हो सकते हैं: नए {... MyFunction = नए फ़ंक <string, bool> (s => value.A == s)} कार्यों का चयन करें, हालांकि आप इसे संदर्भित नहीं कर सकते। आपके कार्यों में नए गुण (हम "value.A" के बदले "A" का उपयोग नहीं कर सकते हैं)।
cfeduke

2
खैर, क्या यह सिर्फ एक संपत्ति नहीं है जो एक प्रतिनिधि होने के लिए होता है? यह वास्तव में एक विधि नहीं है।
मार्क Gravell

1
मैंने रनटाइम पर प्रकार बनाने के लिए Reflection.Emit का उपयोग किया है, लेकिन विश्वास है कि अब मैं रनटाइम लागत से बचने के लिए AOP समाधान पसंद करूंगा।
नॉर्मन एच।

11

सबसे अच्छा समाधान सिर्फ अनाम वर्गों का उपयोग नहीं करना है।

public class Test
{
    class DummyInterfaceImplementor : IDummyInterface
    {
        public string A { get; set; }
        public string B { get; set; }
    }

    public void WillThisWork()
    {
        var source = new DummySource[0];
        var values = from value in source
                     select new DummyInterfaceImplementor()
                     {
                         A = value.A,
                         B = value.C + "_" + value.D
                     };

        DoSomethingWithDummyInterface(values.Cast<IDummyInterface>());

    }

    public void DoSomethingWithDummyInterface(IEnumerable<IDummyInterface> values)
    {
        foreach (var value in values)
        {
            Console.WriteLine("A = '{0}', B = '{1}'", value.A, value.B);
        }
    }
}

ध्यान दें कि आपको क्वेरी के परिणाम को इंटरफ़ेस के प्रकार में डालने की आवश्यकता है। ऐसा करने का एक बेहतर तरीका हो सकता है, लेकिन मुझे यह नहीं मिला।


2
आप values.OfType<IDummyInterface>()कास्ट के बजाय उपयोग कर सकते हैं । यह केवल आपके संग्रह में उन वस्तुओं को लौटाता है जो वास्तव में उस प्रकार के लिए डाली जा सकती हैं। यह सब आप क्या चाहते हैं उस पर निर्भर करता है।
क्रिस्टोफर L

7

विशेष रूप से पूछे गए प्रश्न का उत्तर नहीं है। लेकिन क्या आप मॉकिंग फ्रेमवर्क को देख रहे हैं? मैं MOQ का उपयोग करता हूं, लेकिन उनमें से लाखों वहां हैं और वे आपको इन-लाइन (आंशिक रूप से या पूरी तरह से) इन-लाइन को लागू करने की अनुमति देते हैं। उदाहरण के लिए।

public void ThisWillWork()
{
    var source = new DummySource[0];
    var mock = new Mock<DummyInterface>();

    mock.SetupProperty(m => m.A, source.Select(s => s.A));
    mock.SetupProperty(m => m.B, source.Select(s => s.C + "_" + s.D));

    DoSomethingWithDummyInterface(mock.Object);
}

0

एक अन्य विकल्प यह है कि एक एकल, ठोस कार्यान्वयन वर्ग बनाया जाए जो कंस्ट्रक्टर में लैम्ब्डा लेता है।

public interface DummyInterface
{
    string A { get; }
    string B { get; }
}

// "Generic" implementing class
public class Dummy : DummyInterface
{
    private readonly Func<string> _getA;
    private readonly Func<string> _getB;

    public Dummy(Func<string> getA, Func<string> getB)
    {
        _getA = getA;
        _getB = getB;
    }

    public string A => _getA();

    public string B => _getB();
}

public class DummySource
{
    public string A { get; set; }
    public string C { get; set; }
    public string D { get; set; }
}

public class Test
{
    public void WillThisWork()
    {
        var source = new DummySource[0];
        var values = from value in source
                     select new Dummy // Syntax changes slightly
                     (
                         getA: () => value.A,
                         getB: () => value.C + "_" + value.D
                     );

        DoSomethingWithDummyInterface(values);

    }

    public void DoSomethingWithDummyInterface(IEnumerable<DummyInterface> values)
    {
        foreach (var value in values)
        {
            Console.WriteLine("A = '{0}', B = '{1}'", value.A, value.B);
        }
    }
}

यदि आप कभी भी करने जा रहे हैं , तो इसे परिवर्तित कर दिया जाता DummySourceहै DummyInterface, तो यह आसान होगा कि केवल एक वर्ग ऐसा DummySourceहो जो कंस्ट्रक्टर में लेता है और इंटरफ़ेस को लागू करता है।

लेकिन, अगर आपको कई प्रकारों को बदलने की आवश्यकता है, तो DummyInterfaceयह बहुत कम बॉयलर प्लेट है।

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