Der einfachste Weg, eine gemeinsame Basisklasse aus einer Sammlung von Typen zu bekommen

stimmen
3

Ich baue eine benutzerdefinierte Eigenschaft Raster, das die Eigenschaften der Elemente in einer Sammlung zeigt. Was ich möchte, ist nur die Eigenschaften im Netz zeigen, tun, die unter jedem Elemente gemeinsam sind. Ich gehe davon aus, den besten Weg, dies zu tun wäre, die die gemeinsame Basisklasse von jeder Art in der Sammlung zu finden und es ist Eigenschaften. Gibt es einen einfacheren Weg? Können Sie mir einen Code Beispiel für den besten Ansatz geben, dies zu tun?

Veröffentlicht am 09/12/2008 um 17:44
quelle vom benutzer
In anderen Sprachen...                            


6 antworten

stimmen
3

Sie können mit einer Methode, dies zu tun, die Prüfung für die gemeinsame Basisklassen hält. Ich schrieb diese nach oben, schnell, das Baseclass Merkmale der Type-Klasse. Sie müssen nicht ein Array verwenden, um eine Liste oder andere IEnumerable können mit kleinen Änderungen an dieser Arbeit.

Getestet habe ich es mit:

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

Und bekam die richtige Antwort von DbCommand. Hier ist mein Code.

    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;
    }
Beantwortet am 09/12/2008 um 18:13
quelle vom benutzer

stimmen
2

Der Code geschrieben, die meisten spezifische gemeinsame Basis für eine Reihe von Arten zu bekommen hat einige Probleme. Insbesondere bricht es, wenn ich typeof (Objekt) als einer der Typen bestehen. Ich glaube, die folgende ist einfacher und (besser) zu korrigieren.

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;
}

Ich habe auch getestet mit:

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

Und bekam typeof(DbCommand). Und mit:

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

Und bekam typeof(Compoment). Und mit:

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

Und bekam typeof(MarshalByRefObject). Und mit

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

Und bekam typeof(object).

Beantwortet am 31/03/2009 um 17:26
quelle vom benutzer

stimmen
2

Um die gemeinsamen Eigenschaften aus einer Sammlung von Objekten zu erhalten, können Sie eine Methode wie folgt verwenden:

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();
}

Dann, wenn Sie die Zeichenfolge einer Immobilie haben Sie etwas mit dem tun mögen, können Sie eines der Objekte in der Sammlung und Verwendung Reflexion nehmen Sie das Eigentum von ihrem String Namen zu nennen.

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

In ähnlicher Weise der Code in der GetCommonPropertiesByNameMethode kann modifiziert werden , um gemeinsame Elemente zu erhalten, Methoden, verschachtelte Typen, Felder, etc ...

Beantwortet am 09/12/2008 um 19:27
quelle vom benutzer

stimmen
0

Ich benutze so etwas wie diese, aber Tonys Antwort ist wahrscheinlich besser:

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;
    }
}
Beantwortet am 10/12/2008 um 12:50
quelle vom benutzer

stimmen
0

Hier ist ein Weg, um den gemeinsamen Satz von Eigenschaften aus einer Liste von Typen zu bekommen:

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;
    }
}

Diese iteriert über alle Eigenschaften in allen Arten und endet erst mit den auftretenden mehrfach gleich der Anzahl der Arten auf.

Wenn Sie kompakte LINQ-Abfragen bevorzugen, können Sie den folgenden äquivalenten Ausdruck verwenden:

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();
Beantwortet am 09/12/2008 um 19:02
quelle vom benutzer

stimmen
0

Gut,

Sie könnten ähnlich wie IComparable in Schnittstelle schaffen, sondern es stattdessen wie IPropertyComparable etwas nennen und dann die Klassen, die es Reflektion verwenden implementieren, wie so ihre Eigenschaftsnamen vergleichen ...

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

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

     ...

Ich lasse Sie den Rest herauszufinden. Es könnte wohl vielleicht ein wenig mehr elegant wie auch immer, verwendet LINQ sein ...

  • Matt
Beantwortet am 09/12/2008 um 18:00
quelle vom benutzer

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