2009-04-17 18 views
12

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

मेरी कक्षा (बी) किसी अन्य वर्ग (ए) से विरासत में है।

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

बी के समान ए से प्राप्त होने वाले कई प्रकार हैं, और मैं उनमें से प्रत्येक के लिए Execute() को कार्यान्वित करना चाहता हूं।

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

उत्तर

4

नहीं, वर्चुअल एक्सटेंशन विधियों जैसी कोई चीजें नहीं हैं। आप अधिभार का उपयोग कर सकते हैं, लेकिन यह polymorphism का समर्थन नहीं करता है। ऐसा लगता है कि आप विभिन्न कोड (निर्भरता) के लिए निर्भरता इंजेक्शन (आदि) की तरह कुछ देखना चाहते हैं की तरह हो सकता है अलग अलग वातावरण में जोड़ा - और नियमित रूप से आभासी तरीकों में इसका इस्तेमाल करते हैं:

class B { 
    public B(ISomeUtility util) { 
     // store util 
    } 
    public override void Execute() { 
     if(util != null) util.Foo(); 
    } 
} 

तो प्रदान करने के लिए एक डि ढांचे का उपयोग एक सर्वर-विशिष्ट ISomeUtility रनटाइम पर B पर कार्यान्वयन। आप एक केंद्रीय static रजिस्ट्री (आईओसी, लेकिन कोई डीआई) के साथ एक ही बात कर सकते हैं:

override void Execute() { 
     ISomeUtility util = Registry.Get<ISomeUtility>(); 
     if(util != null) util.Foo(); 
    } 

(जहां Registry आदि लिखने के लिए आवश्यकता होगी; प्लस सर्वर पर, रजिस्टर ISomeUtility कार्यान्वयन)

+0

धन्यवाद मार्क। मैं इस तरह कुछ लागू करूंगा। यह मेरे लिए थोड़ा और मुश्किल है, क्योंकि मैं इन वर्गों को क्रमबद्ध करता हूं, और सर्वर से तार पर उन्हें क्लाइंट और वापस भेजता हूं। तो पारंपरिक डी थोड़ा मुश्किल हो सकता है, लेकिन मुझे लगता है कि मैं कक्षा बी के समतुल्य समकक्ष को लागू कर सकता हूं, (शायद बी से विरासत में), और जब क्लाइंट सर्वर को बी का उदाहरण भेजता है, तो मुझे इसे एक के साथ बदलना होगा सर्वरबी का नया उदाहरण। – Lucas

+0

रजिस्ट्री दृष्टिकोण serialization के साथ ठीक काम करता है। मैं डब्ल्यूसीएफ ऑब्जेक्ट्स के साथ असेंबली साझा करने के लिए उस दृष्टिकोण का उपयोग करता हूं ... –

0

आभासी ओओपी तरीके से विरासत का तात्पर्य है और विस्तार विधियां "बस" स्थैतिक विधियां हैं जो थोड़ी सी सिंटैक्टिक चीनी के माध्यम से संकलक आपको अपने पहले पैरामीटर के प्रकार के उदाहरण पर कॉल करने का नाटक करने की अनुमति देती है। तो नहीं, वर्चुअल एक्सटेंशन विधियां प्रश्न से बाहर हैं।

अपनी समस्या के संभावित समाधान के लिए मार्क ग्रेवेल द्वारा उत्तर देखें।

0

आप एक सेवा रजिस्टर लागू कर सकते हैं। उदाहरण (सर्वर साइड):

static IDictionary<Type, IService> serviceRegister; 

public void ServerMethod(IBusinessType object) 
{ 
    serviceRegister[obect.GetType()].Execute(object); 
} 

आप क्या जरूरत है अपने सर्वर में सेवाओं, जो सर्वर साइड कार्यक्षमता लागू, बजाय विस्तार तरीकों में से नहीं बल्कि कर रहे हैं। मैं एक्सटेंशन विधियों में ज्यादा तर्क नहीं डालूंगा।

0

मुझे यह जांचने दो: आपके पास ए से विरासत में एक श्रेणी पदानुक्रम है, जो संभावित रूप से आपके व्यापार डोमेन के अनुसार संरचित है। फिर आप कक्षाओं को निष्पादित करने के आधार पर व्यवहार जोड़ना चाहते हैं। अब तक आपने विस्तार विधियों का उपयोग किया है, लेकिन अब आप पाते हैं कि आप उन्हें अपने वर्ग पदानुक्रम के साथ अलग-अलग नहीं कर सकते हैं। आप सर्वर पर किस प्रकार के व्यवहार संलग्न कर रहे हैं?

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

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

2

मैं निम्नलिखित की तरह कुछ सुझाव दूंगा। इंटरमीडिएट क्लास पदानुक्रम प्रकारों का पता लगाने के लिए समर्थन जोड़कर इस कोड को बेहतर किया जा सकता है जिसमें प्रेषण मैपिंग नहीं है और रनटाइम पदानुक्रम के आधार पर निकटतम प्रेषण विधि को कॉल किया जा रहा है। ExecuteInteral() के अधिभार का पता लगाने और उन्हें स्वचालित रूप से प्रेषण मानचित्र में जोड़ने के लिए प्रतिबिंब का उपयोग करके भी सुधार किया जा सकता है।

using System; 
using System.Collections.Generic; 

namespace LanguageTests2 
{ 
    public class A { } 

    public class B : A {} 

    public class C : B {} 

    public static class VirtualExtensionMethods 
    { 
     private static readonly IDictionary<Type,Action<A>> _dispatchMap 
      = new Dictionary<Type, Action<A>>(); 

     static VirtualExtensionMethods() 
     { 
      _dispatchMap[typeof(A)] = x => ExecuteInternal((A)x); 
      _dispatchMap[typeof(B)] = x => ExecuteInternal((B)x); 
      _dispatchMap[typeof(C)] = x => ExecuteInternal((C)x); 
     } 

     public static void Execute(this A instance) 
     { 
      _dispatchMap[instance.GetType()](instance); 
     } 

     private static void ExecuteInternal(A instance) 
     { 
      Console.WriteLine("\nCalled ToString() on: " + instance); 
     } 

     private static void ExecuteInternal(B instance) 
     { 
      Console.WriteLine("\nCalled ToString() on: " + instance); 
     } 

     private static void ExecuteInternal(C instance) 
     { 
      Console.WriteLine("\nCalled ToString() on: " + instance); 
     } 
    } 

    public class VirtualExtensionsTest 
    { 
     public static void Main() 
     { 
      var instanceA = new A(); 
      var instanceB = new B(); 
      var instanceC = new C(); 

      instanceA.Execute(); 
      instanceB.Execute(); 
      instanceC.Execute(); 
     } 
    } 
} 
3

आप नए गतिशील प्रकार की कार्यक्षमता का उपयोग तरीकों के प्रकार की एक रजिस्ट्री का निर्माण करने से बचने के लिए कर सकते हैं:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using visitor.Extension; 

namespace visitor 
{ 
    namespace Extension 
    { 
     static class Extension 
     { 
      public static void RunVisitor(this IThing thing, IThingOperation thingOperation) 
      { 
       thingOperation.Visit((dynamic)thing); 
      } 

      public static ITransformedThing GetTransformedThing(this IThing thing, int arg) 
      { 
       var x = new GetTransformedThing {Arg = arg}; 
       thing.RunVisitor(x); 
       return x.Result; 
      } 
     } 
    } 

    interface IThingOperation 
    { 
     void Visit(IThing iThing); 
     void Visit(AThing aThing); 
     void Visit(BThing bThing); 
     void Visit(CThing cThing); 
     void Visit(DThing dThing); 
    } 

    interface ITransformedThing { } 

    class ATransformedThing : ITransformedThing { public ATransformedThing(AThing aThing, int arg) { } } 
    class BTransformedThing : ITransformedThing { public BTransformedThing(BThing bThing, int arg) { } } 
    class CTransformedThing : ITransformedThing { public CTransformedThing(CThing cThing, int arg) { } } 
    class DTransformedThing : ITransformedThing { public DTransformedThing(DThing dThing, int arg) { } } 

    class GetTransformedThing : IThingOperation 
    { 
     public int Arg { get; set; } 

     public ITransformedThing Result { get; private set; } 

     public void Visit(IThing iThing) { Result = null; } 
     public void Visit(AThing aThing) { Result = new ATransformedThing(aThing, Arg); } 
     public void Visit(BThing bThing) { Result = new BTransformedThing(bThing, Arg); } 
     public void Visit(CThing cThing) { Result = new CTransformedThing(cThing, Arg); } 
     public void Visit(DThing dThing) { Result = new DTransformedThing(dThing, Arg); } 
    } 

    interface IThing {} 
    class Thing : IThing {} 
    class AThing : Thing {} 
    class BThing : Thing {} 
    class CThing : Thing {} 
    class DThing : Thing {} 
    class EThing : Thing { } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      var things = new List<IThing> { new AThing(), new BThing(), new CThing(), new DThing(), new EThing() }; 
      var transformedThings = things.Select(thing => thing.GetTransformedThing(4)).Where(transformedThing => transformedThing != null).ToList(); 
      foreach (var transformedThing in transformedThings) 
      { 
       Console.WriteLine(transformedThing.GetType().ToString()); 
      } 
     } 
    } 
} 
+1

आप मुझे पसंद करते हैं, मुझे यह उदाहरण पसंद है लेकिन आप अपना पॉइंट बहुत अधिक सीप्लर डाल सकते थे। –

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