2013-03-31 6 views
34

बनाना मैं गतिशील रूप से प्रॉक्सी क्लास बनाने की कोशिश कर रहा हूं। मुझे पता है कि ऐसा करने के लिए वहां कुछ बहुत अच्छे ढांचे हैं लेकिन यह एक सीखने का अभ्यास के रूप में पूरी तरह से एक पालतू परियोजना है, इसलिए इसे स्वयं करना चाहूंगा।गतिशील रूप से प्रॉक्सी क्लास

, उदाहरण के लिए, मैं निम्नलिखित वर्ग एक अंतरफलक को लागू करने के लिए है:

interface IMyInterface 
{ 
    void MyProcedure(); 
} 

class MyClass : IMyInterface 
{ 
    void MyProcedure() 
    { 
     Console.WriteLine("Hello World"); 
    } 
} 

ताकि उन्हें लॉग इन करने में इस वर्ग के तरीकों को बीच में रोकने के लिए, मैं किसी अन्य वर्ग बनाने रहा हूँ (एक प्रॉक्सी वर्ग की मेरी संस्करण) जो एक ही इंटरफेस लागू करता है लेकिन 'वास्तविक' वर्ग का संदर्भ होता है। यह वर्ग एक क्रिया (उदा। लॉगिंग) करता है और फिर वास्तविक विधि पर एक ही विधि को कॉल करता है।

उदाहरण के लिए:

class ProxyClass : IMyInterface 
{ 
    private IMyInterface RealClass { get; set; } 

    void MyProcedure() 
    { 
     // Log the call 
     Console.WriteLine("Logging.."); 

     // Call the 'real' method 
     RealClass.MyProcedure(); 
    } 
} 

फोन करने वाले तो प्रॉक्सी वर्ग पर सभी तरीकों (मैं एक बुनियादी घर काढ़ा आईओसी कंटेनर का उपयोग कर रहा वास्तविक वर्ग के स्थान पर प्रॉक्सी वर्ग सुई) कॉल के बजाय। मैं इस विधि का उपयोग कर रहा हूं क्योंकि मैं एक ही इंटरफेस को लागू करने वाले दूसरे वर्ग में रन टाइम पर RealClass को स्वैप करने में सक्षम होना चाहता हूं।

रन समय पर ProxyClass बनाने का कोई तरीका है और इसकी RealClass संपत्ति को पॉप्युलेट करें ताकि इसे वास्तविक कक्षा के लिए प्रॉक्सी के रूप में उपयोग किया जा सके? क्या ऐसा करने का कोई आसान तरीका है या मुझे Reflection.Emit जैसे कुछ उपयोग करने की आवश्यकता है और एमएसआईएल उत्पन्न करें?

+0

गतिशील रूप से उत्पन्न करने का क्या मतलब है? क्या आपका मतलब है कि आपके पास एक टाइप ऑब्जेक्ट है और इस प्रकार की ऑब्जेक्ट को तुरंत चालू करना चाहते हैं? – JJ15k

+0

हां। मैं IMYInterface से रनटाइम पर प्रॉक्सी क्लास का एक उदाहरण बनाना चाहता हूं, एक वास्तविक वर्ग के संदर्भ में अपनी 'रियल क्लास' संपत्ति को पॉप्युलेट करें ताकि इसका उपयोग वास्तविक वर्ग में सभी कॉल को अवरुद्ध करने के लिए किया जा सके। मैं आपको धन्यवाद देने के लिए प्रश्न संपादित करूंगा। –

+1

कैसल की डायनामिक प्रॉक्सी देखें http://www.castleproject.org/projects/dynamicproxy/ –

उत्तर

44

System.Runtime.Remoting.Proxies.RealProxy पर एक नज़र डालें। आप इसका उपयोग ऐसे उदाहरण बनाने के लिए कर सकते हैं जो कॉलर के परिप्रेक्ष्य से लक्ष्य प्रकार प्रतीत होता है। RealProxy.Invoke एक बिंदु प्रदान करता है जिससे आप अंतर्निहित प्रकार पर लक्ष्य विधि का आह्वान कर सकते हैं या कॉल के पहले/बाद में अतिरिक्त प्रसंस्करण कर सकते हैं (उदाहरण के लिए लॉगिंग)। सांत्वना देने तो

IMyInterface intf = LoggingProxy<IMyInterface>.Create(new MyClass()); 
intf.MyProcedure(); 

उत्पादन होगा:

public class LoggingProxy<T> : RealProxy 
{ 
    private readonly T _instance; 

    private LoggingProxy(T instance) 
     : base(typeof(T)) 
    { 
     _instance = instance; 
    } 

    public static T Create(T instance) 
    { 
     return (T)new LoggingProxy<T>(instance).GetTransparentProxy(); 
    } 

    public override IMessage Invoke(IMessage msg) 
    { 
     var methodCall = (IMethodCallMessage)msg; 
     var method = (MethodInfo)methodCall.MethodBase; 

     try 
     { 
      Console.WriteLine("Before invoke: " + method.Name); 
      var result = method.Invoke(_instance, methodCall.InArgs); 
      Console.WriteLine("After invoke: " + method.Name); 
      return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("Exception: " + e); 
      if (e is TargetInvocationException && e.InnerException != null) 
      { 
       return new ReturnMessage(e.InnerException, msg as IMethodCallMessage); 
      } 

      return new ReturnMessage(e, msg as IMethodCallMessage); 
     } 
    } 
} 

यहाँ कैसे आप इसका इस्तेमाल होता है:

यहाँ एक प्रॉक्सी है कि प्रत्येक विधि मंगलाचरण के बाद/पहले कंसोल के लिए लॉग का एक उदाहरण है हो:

आह्वान से पहले: MyProcedure
नमस्ते विश्व
invo के बाद के: MyProcedure

+0

यही वह है जिसे मैं ढूंढ रहा था और मुझे सही दिशा में इंगित किया है। धन्यवाद। –

+18

हालांकि, एक महत्वपूर्ण सीमा यह है कि प्रॉक्सी में लपेटने का प्रकार मार्शलबीरफॉबजेक्ट से प्राप्त होना चाहिए। – Piedone

+0

@Piedone, लपेटने के लिए टाइप एक इंटरफ़ेस होना चाहिए या MarshalByRefObject से प्राप्त होना चाहिए – chapluck

0

शायद मैंने प्रश्न को गलत समझा है, एक निर्माता के बारे में कैसे?

class ProxyClass : IMyInterface 
{ 
    public ProxyClass(IMyInterface someInterface) 
    { 
     RealClass = someInterface; 
    } 
    // Your other code... 
} 
0

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

public class A 
{ 
    public virtual void B() 
    { 
     Console.WriteLine("Original method was called."); 
    } 
} 

class Program 
{ 

    static void Main(string[] args) 
    { 
     // Create simple assembly to hold our proxy 
     AssemblyName assemblyName = new AssemblyName(); 
     assemblyName.Name = "DynamicORMapper"; 
     AppDomain thisDomain = Thread.GetDomain(); 
     var asmBuilder = thisDomain.DefineDynamicAssembly(assemblyName, 
        AssemblyBuilderAccess.Run); 

     var modBuilder = asmBuilder.DefineDynamicModule(
        asmBuilder.GetName().Name, false); 

     // Create a proxy type 
     TypeBuilder typeBuilder = modBuilder.DefineType("ProxyA", 
      TypeAttributes.Public | 
      TypeAttributes.Class | 
      TypeAttributes.AutoClass | 
      TypeAttributes.AnsiClass | 
      TypeAttributes.BeforeFieldInit | 
      TypeAttributes.AutoLayout, 
      typeof(A)); 
     MethodBuilder methodBuilder = typeBuilder.DefineMethod("B", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.ReuseSlot); 
     typeBuilder.DefineMethodOverride(methodBuilder, typeof(A).GetMethod("B")); 


     // Generate a Console.Writeline() and base.B() calls. 
     ILGenerator ilGenerator = methodBuilder.GetILGenerator(); 
     ilGenerator.Emit(OpCodes.Ldarg_0); 
     ilGenerator.EmitWriteLine("We caught an invoke! B method was called."); 

     ilGenerator.EmitCall(OpCodes.Call, typeBuilder.BaseType.GetMethod("B"), new Type[0]); 
     ilGenerator.Emit(OpCodes.Ret); 

     //Create a type and casting it to A. 
     Type type = typeBuilder.CreateType(); 
     A a = (A) Activator.CreateInstance(type); 

     // Test it 
     a.B(); 
     Console.ReadLine(); 
    } 
} 
1

आप वर्णित in this question के रूप में गतिशील वस्तुओं का उपयोग कर सकते हैं, लेकिन एक गतिशील रूप से निर्मित, दृढ़ता से टाइप वस्तु के लिए आप, Reflection.Emit उपयोग करने के लिए के रूप में आप पर शक होगा। This blog में उदाहरण कोड है जो गतिशील निर्माण और प्रकार के तत्कालता को दिखाता है।

मैंने पढ़ा है कि Roslyn में ऐसी विशेषताएं हैं जो गतिशील प्रॉक्सी का निर्माण आसान बनाती हैं, इसलिए शायद वहां एक नज़र डालें।

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