Use Attribute+reflection to improve code reuse

Source: Internet
Author: User
Tags foreach bool continue reflection sort

This article two purposes, one is the idea of open design, the second is the example code can be used.

The idea of design comes from the first version of "Effective C #" item 24: Use declarative programming instead of imperative programming. In particular, you want to provide a default sort of multiple attributes, not just one attribute, but one that overrides the Icomparable<t> interface that the object property implements, and then calls IComparable to compare without implementing the interface. The sort class implements generics and is type-safe.

The general idea: attribute used to decorate the class we want to get metadata, use reflection to extract metadata, implement some component functions that are independent of object according to the extracted metadata.

So, the effect of this example is to decorate the class object with attribute, set the default sort attribute of the object, and sort it according to these default sorts.

[DefaultSort (New string[] {"ID", "Name"})]
Class Sortdata
{public
    int ID {get; set;}
   
    public string Name {get; set;}
   
    public string Value {get; set;}
   
    public override string ToString ()
    {return
        String.Format ("id:{0},name:{1},value:{2}", ID, Name, Value);
}

For the Sortdata object, we want to sort by its ID, if the ID is equal, and then sort by the Name property. As its name implies, this is the default behavior, we do not need to implement the Sortdata icomparable<sortdata> interface, in the future to change the collation, as long as the change in the DEFAULTSORT of the property name array of content is enough, very convenient.

The Defaultattribute recorded in the original book can only be sorted according to a property name, which is not practical enough to record the names of multiple properties like the following class.

[AttributeUsage (AttributeTargets.Class | Attributetargets.struct, Allowmultiple=false)] public
    class DefaultSortAttribute:System.Attribute
    {
        Private string[] M_propnames;
   
        Public string[] Propnames
        {get
            {return m_propnames;}
            set {m_propnames = value;}
        }
   
        Public Defaultsortattribute (String propname)
        {
            m_propnames = new string[] {propname};
        }
   
        Public Defaultsortattribute (string[] propnames)
        {
            m_propnames = propnames;
        }
    }

Note that you still have a constructor that you want to sort with only one attribute, and when you decorate a class, it's enough to put [DEFAULTSORT (new string[] {"id", "Name"}), and [DEFAULTSORT ("id")] like that on the class.

Since the use of attribute decorated class, you need to know such metadata, the following needs to use reflection read to the default attribute name to be sorted, compared to the original book, the improvement is to use the generic and precedence properties of the Icomparable<t> interface to compare the sort.

Using System;
Using System.Linq;
Using System.Collections;
Using System.Collections.Generic;
Using System.ComponentModel;
   
Using System.Reflection;
        Namespace Projky.extensions {public class defaultsortcomparer<t>: IComparer, icomparer<t> {
        Private ReadOnly propertydescriptor[] m_sortprops;
        Private readonly bool M_reverse = FALSE;
   
        Private readonly bool M_valuetype = FALSE;
        Public Defaultsortcomparer (): this (false) {} public defaultsortcomparer (bool reverse)
            {m_reverse = reverse;
            Type T = typeof (T);
   
            M_valuetype = T.isvaluetype;
   
            Object[] A = T.getcustomattributes (typeof (Defaultsortattribute), false); Force check, do not support classes that are not decorated with Defaultsortattribute if (a.length!= 1) throw new NotSupportedException (t.na
   
            ME);
   
            Defaultsortattribute sortname = a[0] as Defaultsortattribute; String[] Propnames = sortname.propnames;
   
            M_sortprops = new Propertydescriptor[propnames.length];
   
            PropertyDescriptorCollection props = typedescriptor.getproperties (t);
                    for (int i = 0; i < propnames.length i++) {foreach (PropertyDescriptor p in props) {
                    if (P.name = = Propnames[i]) {m_sortprops[i] = p;
                    Break
            int Icomparer.compare (object left, object right) {
   
                if (hasnull (right) = = true) {int nullcompare = Comparewithnull (left, right); Return m_reverse?
            -nullcompare:nullcompare; } if (left. GetType ()!= right.
   
            GetType ()) throw new ArgumentException ("Left and right not match."); if (typeof (T). IsAssignableFrom (left. GetType ()) = = false) throw NEW ArgumentException ("Type not compatible.");
        return Compare ((t) left, (t) right); public int Compare (t x, t y) {if (M_valuetype = = False && hasnull (x, y) = = True
                {int nullcompare = Comparewithnull (x, y); Return m_reverse?
            -nullcompare:nullcompare; foreach (Var prop in m_sortprops) {object xvalue = Prop.
                GetValue (x); Object yvalue = Prop.
   
                GetValue (y);
   
                    if (Hasnull (Xvalue, yvalue) = = true) {int nullcompare = Comparewithnull (Xvalue, Yvalue); Return m_reverse?
                -nullcompare:nullcompare;
   
                Type proptype = Xvalue.gettype (); Priority is given to the Icomaprable<t> interface if (typeof (Icomparable<>). MakeGenericType (Proptype). IsAssignableFrom (Proptype)) {MethodInfo MethodInfo =Proptype.getmethods (). FirstOrDefault (method => method. Name = = "CompareTo" && method. GetParameters (). Length = = 1 && method. GetParameters () [0].
   
                    ParameterType = = Proptype);
   
                    int gretvalue = (int) methodinfo.invoke (xvalue, new object[] {yvalue});
   
                    if (Gretvalue = = 0) continue; Return m_reverse?
                -gretvalue:gretvalue;
                } IComparable xnongeneric = Xvalue as IComparable;
   
                IComparable ynongeneric = Yvalue as IComparable; if (xnongeneric = null) throw new ArgumentException ("property" + Prop.
   
                Name + "is not comparable.");
   
                int retvalue = Xnongeneric.compareto (Yvalue);
   
                if (RetValue = = 0) continue; Return m_reverse?
            -retvalue:retvalue;
        return 0; } int ComparewiThnull (object right) {if (left = null) && (right = null)) RET
   
            Urn 0;
   
            if (left = = null) return-1;
        return 1;
                BOOL Hasnull (object right) {if (left = null | | right = NULL)
            return true;
        return false; }
    }
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.