2012-05-22 20 views
10

छँटाई हम एक DataGridView करने के लिए संग्रह बाँध और छंटाई और छानने अनुमति देने के लिए sourceforge के माध्यम से Andrew Davey'sBindingListView<T> वर्ग का उपयोग कर रहे हैं।"DynamicMethod के लिए अमान्य प्रकार मालिक" त्रुटि जब एक अंतरफलक

यह सामान्य संग्रह के लिए ठीक काम करता है। एक मामले में हालांकि संग्रह हम के लिए बाध्य कर रहे हैं एक अंतरफलक प्रकार है और हम इस त्रुटि मिलती है, तो हम उस पर सुलझाने की कोशिश:

Invalid type owner for DynamicMethod

त्रुटि एंड्रयू डेविस 'कोड में गहरी है, इसलिए यह मुश्किल है हमें पता है कि कहां से शुरू करना है।

 private static Comparison<T> BuildValueTypeComparison(PropertyInfo pi, ListSortDirection direction) 
     { 
      MethodInfo getMethod = pi.GetGetMethod(); 
      Debug.Assert(getMethod != null); 


      DynamicMethod dm = new DynamicMethod("Get" + pi.Name, typeof(int), new Type[] { typeof(T), typeof(T) }, typeof(T), true); 
      //^^^ ======== Here's the line reporting the error=========== ^^^ 

      ILGenerator il = dm.GetILGenerator(); 

      // Get the value of the first object's property. 
      il.Emit(OpCodes.Ldarg_0); 
      il.EmitCall(OpCodes.Call, getMethod, null); 
      // Box the value type 
      il.Emit(OpCodes.Box, pi.PropertyType); 

      // Get the value of the second object's property. 
      il.Emit(OpCodes.Ldarg_1); 
      il.EmitCall(OpCodes.Call, getMethod, null); 
      // Box the value type 
      il.Emit(OpCodes.Box, pi.PropertyType); 

      // Cast the first value to IComparable and call CompareTo, 
      // passing the second value as the argument. 
      il.Emit(OpCodes.Castclass, typeof(IComparable)); 
      il.EmitCall(OpCodes.Call, typeof(IComparable).GetMethod("CompareTo"), null); 

      // If descending then multiply comparison result by -1 
      // to reverse the ordering. 
      if (direction == ListSortDirection.Descending) 
      { 
       il.Emit(OpCodes.Ldc_I4_M1); 
       il.Emit(OpCodes.Mul); 
      } 

      // Return the result of the comparison. 
      il.Emit(OpCodes.Ret); 

      // Create the delegate pointing at the dynamic method. 
      return (Comparison<T>)dm.CreateDelegate(typeof(Comparison<T>)); 
     } 
+0

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

+0

ठीक है, मैं इसे वापस लेता हूं, आप 'समेकित बाइंडिंग लिस्ट व्यू' का उपयोग कर रहे हैं और यह फेंक देता है। – briantyler

उत्तर

2

हार न दें और डेटासेट का उपयोग करने के लिए जाएं! आप सही दिशा में जा रहे हैं! अब, चलो पहला समारोह हस्ताक्षर पर एक नज़र डालें:

DynamicMethod(string name, 
       Type returnType, 
       Type[] parameterTypes, 
       Type owner, 
       bool skipVisibility) 

Error is “Invalid type owner for DynamicMethod" 

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

1.Error उदाहरण

शायद तुम निर्भरता इंजेक्शन का उपयोग कर रहे हैं, और आप इंटरफ़ेस का उपयोग करना चाहते हो सकता है।

हालांकि, यह कोड रनटाइम त्रुटि को दबाएगा।

var viewModelList = GetViewModels(); //returns an IList<IViewModel> <-- has i !! 
var blv = new BindingListView<IViewModel>(viewModelList); 

2.Working उदाहरण

कोशिश कंक्रीट प्रकार का उपयोग करने के लिए अपने कोड नया स्वरूप।

अब, यह कोड तो रनटाइम त्रुटि

var viewModelList = GetViewModels(); //returns an IList<ViewModel> <-- has no i !! 
var blv = new BindingListView<ViewModel>(viewModelList); 

मारा नहीं होगा, आपके क्रमबद्ध करने और फ़िल्टर DataGridView पर पूर्ण रूप से अपने काम करेंगे :)

संपादित ------------ ---------------------------------

पीएस अपने कोड को फिर से डिजाइन करने का प्रयास करने के बारे में:

यदि आप एमवीवीएम/एमवीपी पैटर्न का उपयोग कर रहे हैं, तो निम्न तर्क के बारे में सोचें। IList<IViewModel> "वीएम + पी" पक्ष पर रहना चाहिए। IViewModel का उपयोग करने का उद्देश्य मुख्य रूप से है क्योंकि मैं तर्क के "वीएम + पी" पक्ष परीक्षण इकाई के लिए MockingViewModel : IViewModel कहकर इसे प्रतिस्थापित करने में सक्षम होना चाहता हूं।

अब, BindingListView<ViewModel> वास्तव में "वी" पक्ष पर होना चाहिए, यानी YourView : System.Windows.Form { ... } है। और यह YourBindingSource.DataSource = blv; से बाध्यकारी स्रोत से बंधेगा क्योंकि चूंकि मैं एक WinForm इकाई का परीक्षण नहीं करूँगा, इसमें कोई तर्क है कि मैं उन्हें प्रस्तुतकर्ताओं और दृश्यमानों में पुन: सक्रिय करने की कोशिश करूंगा और दृश्य को जितना संभव हो उतना पतला रखूंगा। तो, मैं बस BindingListView में ViewModel का उपयोग करता हूं, इंटरफ़ेस IViewModel नहीं।

तो BindingListView<ConcreteViewModel> स्वाभाविक रूप से मुझे समझ में आता है कि यह मॉडल इंटरफ़ेस को स्वीकार नहीं करता है।

MVVM एमवीपी डिजाइन और इकाई परीक्षण WinForm के बारे में इस सवाल का संदर्भ लें: Should I unit-test my view in MVP(or VM) or how to keep the code in the view to a minimum?

7

अद्यतन: मैं अंत में यह काम कर सही तरीके से मिल गया है, कृपया नीचे देखें।

DynamicMethod रनटाइम पर गतिशील रूप से एक विधि बनाता है; लाइब्रेरी में आप बनाई गई विधि का उपयोग कर रहे हैं ऑब्जेक्ट T में जोड़ा जा रहा है; हालांकि, T एक इंटरफ़ेस है जो विफल रहता है क्योंकि आप किसी इंटरफ़ेस में कोई विधि नहीं जोड़ सकते हैं।

मुख्य समस्या विधि में है:

private static GetPropertyDelegate BuildGetPropertyMethod(PropertyInfo pi)

तरीका यह लिखा गया था कि यह केवल काम करेंगे जब संग्रह प्रकार T ठोस है के रूप में

आप के लिए कार्यान्वयन को बदलते हैं:

private static GetPropertyDelegate BuildGetPropertyMethod(PropertyInfo pi) 
{ 
    MethodInfo getMethod = pi.GetGetMethod(); 
    Debug.Assert(getMethod != null); 

    DynamicMethod dm = new DynamicMethod(
     "GetProperty_" + typeof(T).Name + "_" + pi.Name, typeof(object), 
     new Type[] { typeof(T) }, 
     pi.Module, 
     true); 

    ILGenerator il = dm.GetILGenerator(); 

    il.Emit(OpCodes.Ldarg_0); 
    il.EmitCall(OpCodes.Callvirt, getMethod, null); 
    if (pi.PropertyType.IsValueType) 
    { 
     il.Emit(OpCodes.Box, pi.PropertyType); 
    } 

    // Return the result of the comparison. 
    il.Emit(OpCodes.Ret); 

    return (GetPropertyDelegate)dm.CreateDelegate(typeof(GetPropertyDelegate)); 
} 

it will work for both concrete types and interfaces

आप निम्न दो विधियों अद्यतन करने की आवश्यकता:

private static Comparison<T> BuildValueTypeComparison(PropertyInfo pi, ListSortDirection direction)

private static Comparison<T> BuildNullableComparison(PropertyInfo pi, ListSortDirection direction)

मैं गलत हो सकता है, लेकिन मुझे लगता है कि गति लाभ इन तरीकों में हासिल की तेजी से संपत्ति पढ़ने से आता है , इसलिए DynamicMethod विधि का उपयोग करके पूरी विधियों को लिखने से वास्तव में इतना लाभ नहीं है; हम उपरोक्त से BuildGetPropertyMethod का पुन: उपयोग कर सकते हैं। तो ऐसा करने के लिए, निम्न हो:

private static Comparison<T> BuildValueTypeComparison(
    PropertyInfo pi, 
    ListSortDirection direction) 
{ 
    GetPropertyDelegate m = BuildGetPropertyMethod(pi); 
    Comparison<T> d = delegate(T x, T y) 
    { 
     object mx = m(x); 
     object my = m(y); 

     IComparable c = (IComparable)mx; 

     if (direction == ListSortDirection.Descending) 
     { 
      return -c.CompareTo(my); 
     } 

     return c.CompareTo(my); 
    }; 

    return d; 
} 

private static Comparison<T> BuildNullableComparison(
    PropertyInfo pi, 
    ListSortDirection direction) 
{ 
    GetPropertyDelegate m = BuildGetPropertyMethod(pi); 
    Comparison<T> d = delegate(T x, T y) 
     { 
      object mx = m(x); 
      object my = m(y); 

      IComparable c = (IComparable)mx; 

      if (c == null) 
      { 
       c = (IComparable)my; 

       if (c == null) 
       { 
        return 0; 
       } 

       return direction == ListSortDirection.Descending 
        ? c.CompareTo(mx) : -c.CompareTo(mx); 
      } 

      return direction == ListSortDirection.Descending 
       ? -c.CompareTo(my) : c.CompareTo(my); 
     }; 

    return d; 
} 

जाहिर है इस पर कुछ परीक्षण करते हैं, लेकिन मैं बहुत यकीन है कि है कि आप क्या चाहते हूँ और इसके बारे में के रूप में तेजी से पिछले कोड के रूप में होना चाहिए।

+0

बहुत बढ़िया। मैंने अपना कोड अपनी टेस्ट प्रोजेक्ट में रखा और इसे आजमाया। यह एक सम्मोहन की तरह काम करता है। – Tom

+0

@ टॉम - चीयर्स :) – briantyler

-1

वे गुणों के लिए एक नई विधि क्यों बना रहे हैं, क्यों? क्या वे सिर्फ उस संपत्तिइन्फो का उपयोग नहीं कर सकते थे और संपत्ति मूल्य प्राप्त कर सकते थे? अगर मैं इसे बना रहा था तो मेरे पास इंटरफेस दिमाग में होगा और उपयोगकर्ताओं को उनका उपयोग करने से प्रतिबंधित नहीं करेगा। वे एक ही तरह की विधि बना रहे हैं जो मूल "प्राप्त करें" विधि को कॉल करता है, मुझे समझ में नहीं आता कि इसका क्या मतलब है।

private static GetPropertyDelegate BuildGetPropertyMethod(PropertyInfo pi) 
     { 
      MethodInfo getMethod = pi.GetGetMethod(); 
      Debug.Assert(getMethod != null); 

      DynamicMethod dm = new DynamicMethod("__blw_get_" + pi.Name, typeof(object), new Type[] { typeof(T) }, typeof(T), true); 
      ILGenerator il = dm.GetILGenerator(); 

      il.Emit(OpCodes.Ldarg_0); 
      il.EmitCall(OpCodes.Call, getMethod, null); 

      // Return the result of the comparison. 
      il.Emit(OpCodes.Ret); 

      // Create the delegate pointing at the dynamic method. 
      return (GetPropertyDelegate)dm.CreateDelegate(typeof(GetPropertyDelegate)); 
     } 

छँटाई के लिए फिक्स्ड:

  private static Comparison<T> BuildComparison(string propertyName, ListSortDirection direction) 
     { 
      PropertyInfo pi = typeof(T).GetProperty(propertyName); 
      Debug.Assert(pi != null, string.Format("Property '{0}' is not a member of type '{1}'", propertyName, typeof(T).FullName)); 

      if (typeof(IComparable).IsAssignableFrom(pi.PropertyType)) 
      { 
       if (pi.PropertyType.IsValueType) 
       { 
        return BuildValueTypeComparison(pi, direction); 
       } 
       else 
       { 
        //CHANGED!!!!! 
        //GetPropertyDelegate getProperty = BuildGetPropertyMethod(pi); 
        return delegate(T x, T y) 
        { 
         int result; 
         //CHANGED!!!!! 
         object value1 = pi.GetValue(x, null);// getProperty(x); 
         //CHANGED!!!!! 
         object value2 = pi.GetValue(y, null); //getProperty(y); 
         if (value1 != null && value2 != null) 
         { 
          result = (value1 as IComparable).CompareTo(value2); 
         } 
         else if (value1 == null && value2 != null) 
         { 
          result = -1; 
         } 
         else if (value1 != null && value2 == null) 
         { 
          result = 1; 
         } 
         else 
         { 
          result = 0; 
         } 

         if (direction == ListSortDirection.Descending) 
         { 
          result *= -1; 
         } 
         return result; 
        }; 
       } 
      } 
      else if (pi.PropertyType.IsGenericType && pi.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) 
      { 
       var compare = typeof(Nullable).GetMethod("Compare", BindingFlags.Static | BindingFlags.Public).MakeGenericMethod(pi.PropertyType.GetGenericArguments()[0]); 
       return delegate (T x, T y) 
       { 
        return (int)compare.Invoke(x,new[] { pi.GetValue(x, null), pi.GetValue(y, null) }); 
       }; 
       //return BuildNullableComparison(pi, direction); 
      } 
      else 
      { 
       return delegate(T o1, T o2) 
       { 
        if (o1.Equals(o2)) 
        { 
         return 0; 
        } 
        else 
        { 
         return o1.ToString().CompareTo(o2.ToString()); 
        } 
       }; 
      } 
     } 
संबंधित मुद्दे