2011-03-30 17 views
15

में विधि के लिए जेनेरिक प्रकार का कॉल प्राप्त करें। मैं गतिशील वस्तुओं के साथ काम करना शुरू कर रहा हूं। नेट और मैं कुछ नहीं कर सकता हूं।डायनामिक ऑब्जेक्ट

मेरे पास एक कक्षा है जो डायनामिक ऑब्जेक्ट से प्राप्त होती है, और मैं TryInvokeMember विधि को ओवरराइड करता हूं।

उदा।

class MyCustomDynamicClass : DynamicObject 
{ 
    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) 
    { 
     // I want to know here the type of the generic argument 
    } 
} 

और वह विधि मैं मंगलाचरण में सामान्य तर्क का प्रकार (यदि हो तो) जानना चाहता हूँ अंदर।

उदा। अगर मैं निम्नलिखित कोड आह्वान, मैं अपने गतिशील वस्तु

dynamic myObject = new MyCustomDynamicClass(); 
myObject.SomeMethod<bool>("arg"); 
myObject.SomeOtherMethod<int>("arg"); 
वर्तमान में

की overrided विधि के अंदर System.Boolean और System.Int32 का मूल्य प्राप्त करने के लिए अगर मैं overrided विधि मैं प्राप्त कर सकते हैं अंदर एक ब्रेकपाइंट जगह चाहते हैं लागू होने वाली विधि का नाम ("कुछ विधि" और "कुछ अन्य विधि", और तर्कों के मान भी, लेकिन सामान्य प्रकार नहीं)।

मैं इन मानों को कैसे प्राप्त कर सकता हूं?

धन्यवाद!

+0

अधिकतर आपको प्रतिबिंब का उपयोग करके विधि को देखने की आवश्यकता है। MethodInfo सामान्य प्रकार के तर्कों तक पहुंच प्रदान करता है। –

+0

समस्या यह है कि विधि मौजूद नहीं है, मेरे पास अभी बाइंडर ऑब्जेक्ट तक पहुंच है, जिसमें एक कॉलइन्फो संपत्ति है, जिसमें कोई जेनेरिक जानकारी नहीं है। – willvv

+1

आप जानते हैं, मैं थोड़ी देर के लिए इस के नमूने का प्रयास कर रहा हूं, और मुझे नहीं पता कि जेनेरिक जानकारी कहां है। यह वास्तव में वास्तव में एक अच्छा सवाल है। – Tejs

उत्तर

11

दरअसल मैंने बाइंडर के पदानुक्रम को देखा और वस्तु के आंतरिक क्षेत्रों में आवश्यक मूल्यों के साथ एक संपत्ति पाई।

समस्या यह है कि संपत्ति का खुलासा नहीं किया गया है क्योंकि यह सी #-विशिष्ट कोड/कक्षाओं का उपयोग करता है, इसलिए गुणों को प्रतिबिंब का उपयोग करके एक्सेस किया जाना चाहिए।

मैं इस जापानी ब्लॉग में कोड मिला: http://neue.cc/category/programming (मैं किसी भी जापानी पढ़ा नहीं है, इसलिए मुझे यकीन है कि नहीं कर रहा हूँ अगर लेखक वास्तव में यह एक ही मुद्दा

यहाँ का वर्णन करता है टुकड़ा है:

var csharpBinder = binder.GetType().GetInterface("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder"); 
var typeArgs = (csharpBinder.GetProperty("TypeArguments").GetValue(binder, null) as IList<Type>); 

typeArgs सामान्य जब विधि लागू इस्तेमाल किया तर्क के प्रकार युक्त एक सूची है।

आशा इस किसी और मदद करता है।

+0

अच्छी नौकरी :) सुंदर नहीं, लेकिन नौकरी करता है! –

+0

वास्तव में मुझे इस कोड में एक पकड़ मिली। यह केवल ढांचे के पूर्ण संस्करण के साथ काम करता है, और मुझे इसे सिल्वरलाइट में उपयोग करने की ज़रूरत है, इसलिए मुझे अभी भी एक वास्तविक जवाब याद आ रहा है :( – willvv

3

ओपन सोर्स फ्रेमवर्क Dynamitey डीएलआर का उपयोग करके आंतरिक/संरक्षित/निजी गुणों को कॉल कर सकता है और इस प्रकार सिल्वरलाइट के साथ काम करता है। लेकिन इंटरफ़ेस स्पष्ट सदस्यों के साथ यह थोड़ा मुश्किल हो जाता है क्योंकि आपको इंटरफ़ेस सदस्य नाम के बजाय, प्रकार के सदस्य के वास्तविक पूर्ण नाम का उपयोग करना होगा। तो अगर आप कर सकते हैं:

var typeArgs = Dynamic.InvokeGet(binder, "Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder.TypeArguments") 
    as IList<Type>; 
+0

यह कमाल है! – albertjan

+0

हाय यह काम नहीं करता है क्योंकि बांधने की मशीन प्रकार नहीं है ICSharpInvokeOrInvokeMemberBinder लेकिन यदि आप टाइप_ग्रेट्स को m_typeArguments में बदलते हैं तो यह काम करता है। – albertjan

+0

उह, आप सही हैं, हालांकि m_typeArguments काम करता है, यह उस प्रॉपर्टी संस्करण की तुलना में एक अलग प्रकार लौटा रहा है, इसलिए मैंने इंटरफ़ेस बतख कास्टिंग उदाहरण हटा दिया। – jbtule

3

googling के बारे में थोड़ी और मैं के लिए .NET और मोनो काफी सामान्य समाधान है:

/// <summary>Framework detection and specific implementations.</summary> 
public static class FrameworkTools 
{ 
    private static bool _isMono = Type.GetType("Mono.Runtime") != null; 

    private static Func<InvokeMemberBinder, IList<Type>> _frameworkTypeArgumentsGetter = null; 

    /// <summary>Gets a value indicating whether application is running under mono runtime.</summary> 
    public static bool IsMono { get { return _isMono; } } 

    static FrameworkTools() 
    { 
     _frameworkTypeArgumentsGetter = CreateTypeArgumentsGetter(); 
    } 

    private static Func<InvokeMemberBinder, IList<Type>> CreateTypeArgumentsGetter() 
    { 
     if (IsMono) 
     { 
      var binderType = typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).Assembly.GetType("Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder"); 

      if (binderType != null) 
      { 
       ParameterExpression param = Expression.Parameter(typeof(InvokeMemberBinder), "o"); 

       return Expression.Lambda<Func<InvokeMemberBinder, IList<Type>>>(
        Expression.TypeAs(
         Expression.Field(
          Expression.TypeAs(param, binderType), "typeArguments"), 
         typeof(IList<Type>)), param).Compile(); 
      } 
     } 
     else 
     { 
      var inter = typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).Assembly.GetType("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder"); 

      if (inter != null) 
      { 
       var prop = inter.GetProperty("TypeArguments"); 

       if (!prop.CanRead) 
        return null; 

       var objParm = Expression.Parameter(typeof(InvokeMemberBinder), "o"); 

       return Expression.Lambda<Func<InvokeMemberBinder, IList<Type>>>(
        Expression.TypeAs(
         Expression.Property(
          Expression.TypeAs(objParm, inter), 
          prop.Name), 
         typeof(IList<Type>)), objParm).Compile(); 
      } 
     } 

     return null; 
    } 

    /// <summary>Extension method allowing to easyly extract generic type arguments from <see cref="InvokeMemberBinder"/>.</summary> 
    /// <param name="binder">Binder from which get type arguments.</param> 
    /// <returns>List of types passed as generic parameters.</returns> 
    public static IList<Type> GetGenericTypeArguments(this InvokeMemberBinder binder) 
    { 
     // First try to use delegate if exist 
     if (_frameworkTypeArgumentsGetter != null) 
      return _frameworkTypeArgumentsGetter(binder); 

     if (_isMono) 
     { 
      // In mono this is trivial. 

      // First we get field info. 
      var field = binder.GetType().GetField("typeArguments", BindingFlags.Instance | 
       BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); 

      // If this was a success get and return it's value 
      if (field != null) 
       return field.GetValue(binder) as IList<Type>; 
     } 
     else 
     { 
      // In this case, we need more aerobic :D 

      // First, get the interface 
      var inter = binder.GetType().GetInterface("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder"); 

      if (inter != null) 
      { 
       // Now get property. 
       var prop = inter.GetProperty("TypeArguments"); 

       // If we have a property, return it's value 
       if (prop != null) 
        return prop.GetValue(binder, null) as IList<Type>; 
      } 
     } 

     // Sadly return null if failed. 
     return null; 
    } 
} 

मज़े। जिस तरह से Impromptu ठंडा है, लेकिन मैं इसका उपयोग नहीं कर सकता।

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