que propiedades programacion modificadores herencia autoimplementadas and acceso c# .net linq reflection

c# - propiedades - que es public en programacion



La forma más sencilla de obtener una clase base común a partir de una colección de tipos (6)

Estoy construyendo una grilla de propiedad personalizada que muestra las propiedades de los elementos en una colección. Lo que quiero hacer es mostrar solo las propiedades en la grilla que son comunes entre cada elemento. Supongo que la mejor manera de hacerlo sería encontrar la clase base común de cada tipo en la colección y mostrar sus propiedades. ¿Hay alguna manera más fácil? ¿Me puede dar un ejemplo de código del mejor enfoque para hacer esto?


Aquí hay una manera de obtener el conjunto común de propiedades de una lista de tipos:

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

Esto itera sobre todas las propiedades en todos los tipos y solo termina con las que ocurren varias veces igual a la cantidad de tipos.

Si prefiere consultas compactas LINQ, puede usar la siguiente expresión equivalente:

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


Bien,

Puede crear una interfaz similar a IComparable pero en su lugar llamarla IPropertyComparable y luego hacer que las clases que la implementan usen la reflexión para comparar sus nombres de propiedad como tal ...

public int Compare(T x, T y) { PropertyInfo[] props = x.GetType().GetProperties(); foreach(PropertyInfo info in props) { if(info.name == y.GetType().Name) .... } ...

Dejaré que descubras el resto. Probablemente podría ser un poco más elegante de todos modos, use LINQ tal vez ...

  • Mate

Para obtener las propiedades comunes de una colección de Objetos, puede usar un método como este:

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

Luego, una vez que tenga la cadena de una propiedad con la que desea hacer algo, puede tomar cualquiera de los objetos en la colección y usar la reflexión para llamar a esa propiedad por su nombre de cadena.

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

Del mismo modo, el código en el método GetCommonPropertiesByName se puede modificar para obtener miembros comunes, métodos, tipos anidados, campos, etc.


Puede hacer esto con un método que siga buscando clases base comunes. Escribí esto rápidamente, usando la función BaseClass de la clase Type. No tiene que usar una matriz, una lista u otra IEnumerable puede funcionar con pequeñas modificaciones a esto.

Lo probé con:

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

Y obtuve la respuesta correcta de DbCommand. Aquí está mi código.

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


Uso algo como esto, pero la respuesta de Tony es probablemente mejor:

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


El código publicado para obtener la base común más específica para un conjunto de tipos tiene algunos problemas. En particular, se rompe cuando paso typeof (objeto) como uno de los tipos. Creo que lo siguiente es más simple y (mejor) correcto.

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

También probé con:

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

Y obtuve typeof(DbCommand) . Y con:

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

Y obtuve typeof(Compoment) . Y con:

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

Y obtuve typeof(MarshalByRefObject) . Y con

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

Y obtuve typeof(object) .