2011-05-31 23 views
12

में एक स्थिर वर्ग को कैसे लपेटें मुझे एक दिलचस्प समस्या है। मुझे स्थिर वर्गों को गतिशील रूप से लपेटने की आवश्यकता है। अर्थात। मेरे कॉलर्स को एक गैर स्थैतिक उदाहरण वापस करें। उदा .:गैर स्थैतिक उदाहरण ऑब्जेक्ट (गतिशील रूप से)

public object CreateInstance(string className) { 
    Type t = assembly.GetType(className); 
    if (IsStatic(t)) { 
    return CreateStaticWrapper(t); 
    } else { 
    return Activator.CreateInstance(t); 
    } 
} 

तो CreateStaticWrapper को लागू करने के लिए के रूप में संकेत है कि मैं क्या जरूरत है।

नोट: मैं दुर्भाग्य से गतिशील वस्तुओं का उपयोग नहीं कर सकता।

तो मेरे विकल्प क्या हैं? मैं आईएल पीढ़ी सीखने के लिए उत्सुक नहीं हूँ? यदि आईएल पीढ़ी (प्रतिबिंब। स्वीकार करें, या अब अन्य तरीके हैं?) क्या जाने का तरीका है क्या किसी के पास पॉइंटर्स हैं?

संपादित करें: यह ध्यान रखना महत्वपूर्ण है कि मैं डेलीगेट्स का एक शब्दकोश वापस कर सकता हूं। तो मैं इसके लिए Delegate.CreateDelegate का उपयोग कर सकता हूं लेकिन मुझे लगता है कि ओवरलोडेड विधियों और जेनेरिक तरीकों को कैसे संभालना है, मैं काम नहीं कर सकता।

संपादित 2: एक और विकल्प एमिट का उपयोग करके किसी प्रकार के खाली कन्स्ट्रक्टर को इंजेक्ट करना होगा, फिर भी कोई पॉइंटर्स? क्या यह स्थिर के रूप में चिह्नित एक प्रकार पर भी संभव है? क्या स्थैतिक कीवर्ड इसे आईएल में बना देता है?

संपादित 3: कुछ संदर्भ के लिए, मैं इसे जावास्क्रिप्ट वातावरण में भेज रहा हूं: my project। इसलिए मैं (जावास्क्रिप्ट में) सक्षम होना चाहता हूं:

var fileHelper = .create('System.IO.File'); 
if (fileHelper.Exists(fileName)) { fileHelper.Delete(fileName); } 

धन्यवाद सब।

+0

क्या आपका लक्ष्य स्थैतिक वर्ग की सामग्री की एक प्रति बनाना है? क्या स्थैतिक वर्ग का एक गैर स्थैतिक समतुल्य है (स्थिर वर्ग के समान गुणों वाला एक गैर स्थैतिक वर्ग? – k3b

+0

रैपर कैसा दिखना चाहिए? मूल वर्ग पर संबंधित स्थिर सदस्यों के लिए प्रॉक्सी इंस्टेंस सदस्य? – Einar

+0

मैंने संपादित किया है (3) कुछ संदर्भ के लिए। असल में मैं इस स्थैतिक वर्ग को जावास्क्रिप्ट वातावरण में भेज रहा हूं। इसलिए हाँ प्रॉक्सी को एक ही हस्ताक्षर होना चाहिए। मैं (जावास्क्रिप्ट में) करने में सक्षम होना चाहता हूं: var fs = .create ('System.IO.File'); fs.Exists ('filename'); – gatapia

उत्तर

1

मैं कहेंगे आईएल पीढ़ी के लिए जाना। प्रॉक्सी बनाना एक बहुत ही सरल परिदृश्य है। मैंने वास्तव में इसके बारे में एक ब्लॉग पोस्ट लिखा: einarwh.posterous.com/patching-polymorphic-pain-at-runtime।परिदृश्य अलग है, लेकिन समाधान लगभग समान है।

आप मूल रूप से ब्लॉग पोस्ट में बिल्कुल कर सकते हैं, सिवाय इसके कि आपको 'इस' संदर्भ को स्टैक पर लोड करने की आवश्यकता नहीं है (क्योंकि आप स्थिर विधि कॉल कर रहे हैं)।

2

System.Dynamic.DynamicObject से प्राप्त एक रैपर वर्ग बनाने का प्रयास करें। रैपर वर्ग में, स्थैतिक वर्ग के तरीकों को कॉल करने के लिए प्रतिबिंब का उपयोग करें।

public class StaticWrapper<T> : System.Dynamic.DynamicObject 
{ 
    private static readonly Type t = typeof(T); 
    public static int MyProperty { get; set; } 
    public override bool TryInvokeMember(System.Dynamic.InvokeMemberBinder binder, object[] args, out object result) 
    { 
     try 
     { 
      result = t.InvokeMember(binder.Name, BindingFlags.Static | BindingFlags.Public, null, null, args); 
      return true; 
     } 
     catch 
     { 
      result = null; 
      return false; 
     } 
    } 
    public override bool TryGetMember(System.Dynamic.GetMemberBinder binder, out object result) 
    { 
     try 
     { 
      var p = t.GetProperty(binder.Name); 
      if (p != null) 
       result = p.GetValue(null, null); 
      else 
      { 
       var f = t.GetField(binder.Name); 
       if (f != null) result = f.GetValue(null); 
       else { result = null; return false; } 
      } 
      return true; 
     } 
     catch 
     { 
      result = null; 
      return false; 
     } 
    } 
    public override bool TrySetMember(System.Dynamic.SetMemberBinder binder, object value) 
    { 
     try 
     { 
      var p = t.GetProperty(binder.Name); 
      if (p != null) 
       p.SetValue(null, value, null); 
      else 
      { 
       var f = t.GetField(binder.Name); 
       if (f != null) f.SetValue(null, value); 
       else return false; 
      } 
      return true; 
     } 
     catch (SystemException) 
     { 
      return false; 
     } 
    } 
} 

यह काम करता है आशा है कि:

आप कुछ इस तरह की जरूरत है।

+0

दुर्भाग्यवश पूरे परिवार की गतिशील वस्तुएं [मेरे लिए एक विकल्प नहीं है] (http://javascriptdotnet.codeplex.com/discussions/235767)। यह मेरी पहली सहज पसंद थी लेकिन महान प्रतिक्रिया के लिए +1 था। – gatapia

+0

'InvokeMember' में' जोड़ें रनटाइम त्रुटि को ठीक करने के लिए BindingFlags.InvokeMethod'। स्टेटिक क्लास सामान्य प्रकार के पैरा के रूप में नहीं हो सकता है उदा। कंसोल। – IlPADlI

1

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

public static object Generate(Type t) 
{ 
    if(IsStatic(t)) 
    { 
     var dictionary = new Dictionary<string, Delegate>(); 
     foreach (var methodInfo in t.GetMethods()) 
     { 
      var d = Delegate.CreateDelegate(t, methodInfo); 
      dictionary[methodInfo.Name] = d; 
     } 
     return dictionary; 
    } 
    return Activator.CreateInstance(t); 
} 

स्टेटिक वर्गों 'सील' कर रहे हैं और इस तरह विरासत में मिला नहीं किया जा सकता। तो मैं नहीं देखता कि आप 'अधिभारित' से क्या मतलब रखते हैं। सामान्य तरीकों के लिए, हमें इसे हमारे शब्दकोश में जोड़ने से पहले methodInfo.MakeGenericMethod(...) को आमंत्रित करने की आवश्यकता है।

... 
if (methodInfo.IsGenericMethod) 
{ 
    d = new Func<MethodInfo, Type[], Delegate>(
     (method, types) => 
     Delegate.CreateDelegate(
      method.DeclaringType, method.MakeGenericMethod(types))); 
} 
dictionary[methodInfo.Name] = d; 
... 

कि आप एक प्रतिनिधि है कि एक प्रकार सरणी ले जाएगा देना होगा (: लेकिन फिर तुम जो मुझे लगता है कि आप नहीं ... या फिर, आप की तरह कुछ कर सकते हैं करते प्रकार पहले से पता करने के लिए की आवश्यकता होगी, सामान्य प्रकार पैरामीटर), और उस से एक कार्यकारी प्रतिनिधि का उत्पादन।

+0

मुझे जेनेरिकों को संभालने के तरीके को वास्तव में पसंद है और मैं इसका उपयोग करूंगा, हालांकि यह अतिरंजित सदस्यों के साथ मेरी मदद नहीं करता है। अर्थात। System.IO.Directory.Delete (dirName) और हटाएं (dirName, रिकर्सिव) का अर्थ है कि मैं केवल एक 'हटाएं' पंजीकृत कर सकता हूं। अब मैं जो कर रहा हूं वह तर्कों के एक ऐरे के साथ केवल एक ही हटा रहा है और फिर गतिशील रूप से सही कार्यान्वयन के लिए प्रतिनिधि है। जावास्क्रिप्ट में हस्ताक्षर बदलने की कुरूपता है। तो अब जेएस में मुझे यह करने की ज़रूरत है: 'निर्देशिका। हटाएं ([dirname]) '। जबकि अन्य सभी कॉल उनके मूल इंटरफेस के लिए सच हैं। – gatapia

1

ठीक है, ठीक है, जिस समाधान के साथ मैं आया हूं, वह निम्नानुसार है और Einar's blog post का अध्ययन और अध्ययन कर रहा था जिसे उन्होंने उपरोक्त टिप्पणी के रूप में पोस्ट किया था। धन्यवाद इनार।

लेकिन मैं मैं मामले में यहाँ मेरी full code solution पोस्ट चाहते हैं यह भविष्य में किसी की मदद कर सकते हैं सोचा:

using System; 
using System.Linq; 
using System.Reflection; 
using System.Reflection.Emit; 

namespace js.net.jish.Command 
{ 
    public class StaticTypeWrapper 
    { 
    private readonly Type staticType; 

    public StaticTypeWrapper(Type staticType) 
    { 
     this.staticType = staticType; 
    } 

    public object CreateWrapper() 
    { 
     string ns = staticType.Assembly.FullName;  
     ModuleBuilder moduleBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(ns), AssemblyBuilderAccess.Run).DefineDynamicModule(ns); 
     TypeBuilder wrapperBuilder = moduleBuilder.DefineType(staticType.FullName, TypeAttributes.Public, null, new Type[0]); 
     foreach (MethodInfo method in staticType.GetMethods().Where(mi => !mi.Name.Equals("GetType"))) 
     { 
     CreateProxyMethod(wrapperBuilder, method); 
     } 
     Type wrapperType = wrapperBuilder.CreateType(); 
     object instance = Activator.CreateInstance(wrapperType); 
     return instance; 
    } 

    private void CreateProxyMethod(TypeBuilder wrapperBuilder, MethodInfo method) 
    { 
     var parameters = method.GetParameters(); 

     var methodBuilder = wrapperBuilder.DefineMethod(method.Name, MethodAttributes.Public | MethodAttributes.Virtual, method.ReturnType, parameters.Select(p => p.ParameterType).ToArray()); 
     var gen = methodBuilder.GetILGenerator(); 

     for (int i = 1; i < parameters.Length + 1; i++) 
     { 
     gen.Emit(OpCodes.Ldarg, i); 
     } 
     gen.Emit(OpCodes.Call, method); 
     gen.Emit(OpCodes.Ret); 
    } 
    } 
} 
संबंधित मुद्दे