Ο ευκολότερος τρόπος για να πάρετε μια κοινή βασική κλάση από μια συλλογή των τύπων

ψήφοι
3

Χτίζω ένα πλέγμα προσαρμοσμένη ιδιότητα που εμφανίζει τις ιδιότητες των αντικειμένων σε μια συλλογή. Αυτό που θέλω να κάνω είναι να εμφανίζονται μόνο οι ιδιότητες του πλέγματος που είναι συχνές σε κάθε στοιχείο. Υποθέτω ο καλύτερος τρόπος για να γίνει αυτό θα ήταν να βρει την τάξη η κοινή βάση για κάθε τύπο της συλλογής και την εμφάνιση των ιδιοτήτων. Υπάρχει κάποιος εύκολος τρόπος; Μπορείτε να μου δώσετε ένα παράδειγμα κώδικα του καλύτερη προσέγγιση για να γίνει αυτό;

Δημοσιεύθηκε 09/12/2008 στις 17:44
πηγή χρήστη
Σε άλλες γλώσσες...                            


6 απαντήσεις

ψήφοι
3

Μπορείτε να το κάνετε αυτό με μια μέθοδο που διατηρεί τον έλεγχο για κοινά μαθήματα βάσης. Έγραψα πάνω από αυτό, γρήγορα, χρησιμοποιώντας τη λειτουργία BaseClass της κατηγορίας Τύπου. Δεν χρειάζεται να χρησιμοποιήσετε μια σειρά, μια λίστα ή άλλες IEnumerable μπορεί να λειτουργήσει με μικρές τροποποιήσεις σε αυτό.

Μου δοκιμαστεί με:

static void Main(string[] args)
{
    Console.WriteLine("Common Types: " + GetCommonBaseClass(new Type[] {typeof(OleDbCommand), typeof(OdbcCommand), typeof(SqlCommand)}).ToString());   
}

Και πήρα τη σωστή απάντηση του DbCommand. Εδώ είναι ο κωδικός μου.

    static Type GetCommonBaseClass(Type[] types)
    {
        if (types.Length == 0)
            return (typeof(object));
        else if (types.Length == 1)
            return (types[0]);

        // Copy the parameter so we can substitute base class types in the array without messing up the caller
        Type[] temp = new Type[types.Length];

        for (int i = 0; i < types.Length; i++)
        {
            temp[i] = types[i];
        }

        bool checkPass = false;

        Type tested = null;

        while (!checkPass)
        {
            tested = temp[0];

            checkPass = true;

            for (int i = 1; i < temp.Length; i++)
            {
                if (tested.Equals(temp[i]))
                    continue;
                else
                {
                    // If the tested common basetype (current) is the indexed type's base type
                    // then we can continue with the test by making the indexed type to be its base type
                    if (tested.Equals(temp[i].BaseType))
                    {
                        temp[i] = temp[i].BaseType;
                        continue;
                    }
                    // If the tested type is the indexed type's base type, then we need to change all indexed types
                    // before the current type (which are all identical) to be that base type and restart this loop
                    else if (tested.BaseType.Equals(temp[i]))
                    {
                        for (int j = 0; j <= i - 1; j++)
                        {
                            temp[j] = temp[j].BaseType;
                        }

                        checkPass = false;
                        break;
                    }
                    // The indexed type and the tested type are not related
                    // So make everything from index 0 up to and including the current indexed type to be their base type
                    // because the common base type must be further back
                    else
                    {
                        for (int j = 0; j <= i; j++)
                        {
                            temp[j] = temp[j].BaseType;
                        }

                        checkPass = false;
                        break;
                    }
                }
            }

            // If execution has reached here and checkPass is true, we have found our common base type, 
            // if checkPass is false, the process starts over with the modified types
        }

        // There's always at least object
        return tested;
    }
Απαντήθηκε 09/12/2008 στις 18:13
πηγή χρήστη

ψήφοι
2

Ο κώδικας δημοσιεύτηκε για να πάρει την πιο ειδική κοινή βάση για ένα σύνολο τύπων έχει κάποια θέματα. Ειδικότερα, σπάει όταν περνώ typeof (αντικείμενο) ως ένας από τους τύπους. Πιστεύω ότι τα ακόλουθα είναι απλούστερη και (καλύτερη) σωστό.

public static Type GetCommonBaseClass (params Type[] types)
{
    if (types.Length == 0)
        return typeof(object);

    Type ret = types[0];

    for (int i = 1; i < types.Length; ++i)
    {
        if (types[i].IsAssignableFrom(ret))
            ret = types[i];
        else
        {
            // This will always terminate when ret == typeof(object)
            while (!ret.IsAssignableFrom(types[i]))
                ret = ret.BaseType;
        }
    }

    return ret;
}

Επίσης, δοκιμάστηκε με:

Type t = GetCommonBaseClass(typeof(OleDbCommand),
                            typeof(OdbcCommand),
                            typeof(SqlCommand));

Και πήρα typeof(DbCommand). Και με:

Type t = GetCommonBaseClass(typeof(OleDbCommand),
                            typeof(OdbcCommand),
                            typeof(SqlCommand),
                            typeof(Component));

Και πήρα typeof(Compoment). Και με:

Type t = GetCommonBaseClass(typeof(OleDbCommand),
                            typeof(OdbcCommand),
                            typeof(SqlCommand),
                            typeof(Component),
                            typeof(Component).BaseType);

Και πήρα typeof(MarshalByRefObject). Και με

Type t = GetCommonBaseClass(typeof(OleDbCommand),
                            typeof(OdbcCommand),
                            typeof(SqlCommand),
                            typeof(Component),
                            typeof(Component).BaseType,
                            typeof(int));

Και πήρα typeof(object).

Απαντήθηκε 31/03/2009 στις 17:26
πηγή χρήστη

ψήφοι
2

Για να πάρετε τις κοινές ιδιότητες από μια συλλογή από αντικείμενα, μπορείτε να χρησιμοποιήσετε μια μέθοδο όπως αυτή:

public static String[] GetCommonPropertiesByName(Object[] objs)
{
    List<Type> typeList = new List<Type>(Type.GetTypeArray(objs));
    List<String> propertyList = new List<String>();
    List<String> individualPropertyList = new List<String>();

    foreach (Type type in typeList)
    {
        foreach (PropertyInfo property in type.GetProperties())
        {
            propertyList.Add(property.Name);
        }
    }

    propertyList = propertyList.Distinct().ToList();

    foreach (Type type in typeList)
    {
        individualPropertyList.Clear();

        foreach (PropertyInfo property in type.GetProperties())
        {
            individualPropertyList.Add(property.Name);
        }

        propertyList = propertyList.Intersect(individualPropertyList).ToList();
    }

    return propertyList.ToArray();
}

Στη συνέχεια, αφού έχετε το string του ακινήτου που θέλετε να κάνετε κάτι με, μπορείτε να πάρετε κάποιο από τα αντικείμενα της συλλογής και χρήσης προβληματισμό για την κλήση αυτή Ακίνητα από String όνομά του.

PropertyInfo p = t.GetType().GetProperty("some Property String Name");
p.GetValue(t, null);
p.SetValue(t, someNewValue, null);

Ομοίως, ο κωδικός της GetCommonPropertiesByNameμεθόδου μπορεί να τροποποιηθεί για να πάρει κοινά μέλη, τις μεθόδους, τα ένθετα είδη, τα πεδία, κλπ ...

Απαντήθηκε 09/12/2008 στις 19:27
πηγή χρήστη

ψήφοι
0

Μπορώ να χρησιμοποιήσω κάτι τέτοιο, αλλά απάντηση Τόνι είναι πιθανώς καλύτερα:

internal class BaseFinder
{
    public static Type FindBase(params Type[] types)
    {
        if (types == null)
            return null;

        if (types.Length == 0)
            return null;

        Dictionary<Type, IList<Type>> baseTypeMap = new Dictionary<Type,IList<Type>>();

        // get all the base types and note the one with the longest base tree
        int maxBaseCount = 0;
        Type typeWithLongestBaseTree = null;
        foreach (Type type in types)
        {
            IList<Type> baseTypes = GetBaseTree(type);
            if (baseTypes.Count > maxBaseCount)
            {
                typeWithLongestBaseTree = type;
                maxBaseCount = baseTypes.Count;
            }
            baseTypeMap.Add(type, baseTypes);
        }

        // walk down the tree until we get to a common base type
        IList<Type> longestBaseTree = baseTypeMap[typeWithLongestBaseTree];
        for (int baseIndex = 0; baseIndex < longestBaseTree.Count;baseIndex++)
        {
            int commonBaseCount = 0;
            foreach (Type type in types)
            {
                IList<Type> baseTypes = baseTypeMap[type];
                if (!baseTypes.Contains(longestBaseTree[baseIndex]))
                    break;
                commonBaseCount++;
            }
            if (commonBaseCount == types.Length)
                return longestBaseTree[baseIndex];
        }
        return null;
    }

    private static IList<Type> GetBaseTree(Type type)
    {
        List<Type> result = new List<Type>();
        Type baseType = type.BaseType;
        do
        {
            result.Add(baseType);
            baseType = baseType.BaseType;
        } while (baseType != typeof(object));
        return result;
    }
}
Απαντήθηκε 10/12/2008 στις 12:50
πηγή χρήστη

ψήφοι
0

Εδώ είναι ένας τρόπος για να πάρετε το κοινό σύνολο ιδιοτήτων από μια λίστα των τύπων:

class TypeHandler
{
    public static List<string> GetCommonProperties(Type[] types)
    {
        Dictionary<string, int> propertyCounts = new Dictionary<string, int>();

        foreach (Type type in types)
        {
            foreach (PropertyInfo info in type.GetProperties())
            {
                string name = info.Name;
                if (!propertyCounts.ContainsKey(name)) propertyCounts.Add(name, 0);
                propertyCounts[name]++;
            }
        }

        List<string> propertyNames = new List<string>();

        foreach (string name in propertyCounts.Keys)
        {
            if (propertyCounts[name] == types.Length) propertyNames.Add(name);
        }

        return propertyNames;
    }
}

Αυτό επαναλαμβάνεται σε όλες τις ιδιότητες σε όλους τους τύπους και τελειώνει μόνο με εκείνα που συμβαίνουν πολλές φορές ίσος με τον αριθμό των ειδών.

Αν προτιμάτε συμπαγή ερωτήματα LINQ, μπορείτε να χρησιμοποιήσετε την ακόλουθη ισοδύναμη έκφραση:

return (from t in types
              from p in t.GetProperties()
              group p by p.Name into pg
              where pg.Count() == types.Length
              select pg.Key).ToList();
Απαντήθηκε 09/12/2008 στις 19:02
πηγή χρήστη

ψήφοι
0

Καλά,

Θα μπορούσατε να δημιουργήσετε στο περιβάλλον παρόμοιο με IComparable αλλά αντί να το ονομάσουμε κάτι σαν IPropertyComparable και στη συνέχεια να έχουν τα μαθήματα που υλοποιούν το χρησιμοποιούν τον προβληματισμό για να συγκρίνουν τα ονόματα ιδιοτήτων τους, έτσι ώστε ...

public int Compare(T x, T y)
{
     PropertyInfo[] props = x.GetType().GetProperties();

     foreach(PropertyInfo info in props)
     {
          if(info.name == y.GetType().Name)
          ....
     }

     ...

Θα σας αφήσω να καταλάβω τα υπόλοιπα. Θα μπορούσε ίσως να είναι λίγο πιο κομψό έτσι κι αλλιώς, χρησιμοποιήστε LINQ ίσως ...

  • Ματ
Απαντήθηκε 09/12/2008 στις 18:00
πηγή χρήστη

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more