2010-10-05 4 views
0

J'essaie de créer une liste de propriétés pour les objets. Je peux très bien créer une liste pour les objets basiques, mais si j'ai une situation où l'objet type A contient une propriété de type objet B qui contient une propriété de type objet A ... ben ... alors j'obtiens une récursion infinie. Ce que j'ai fait est ajouté une propriété statique à tous mes objets appelés "RecursivePropertyList" qui est un List<string> de chaque propriété qui a la récursivité.Fonction pour créer un arbre de propriétés?

Ainsi, par exemple: J'ai une classe Person avec une propriété appelée Vendor de type Vendor. La classe Vendor a une propriété appelée People qui est de type List<Person>.

Dans la classe Person, la valeur RecursivePropertyList est définie sur myList.Add("Vendor.People"). Dans la classe Vendor, j'ai défini la valeur RecursivePropertyList sur myList.Add("People.Vendor").

Ensuite, dans ma fonction qui crée la liste de propriétés, je vérifie pour voir si l'objectname.propertyName actuel est dans le RecursivePropertyList et si c'est le cas, je ne l'ajoute pas à ma liste de propriétés et je ne l'analyse pas dans pour obtenir ses propriétés.

Cela fonctionne très bien dans la situation décrite ci-dessus.

Cependant, il commence à échouer lorsque j'ai la situation suivante: Une classe Application qui a une propriété de type List<ApplicationFunction_Application>. Classe ApplicationFunction possédant une propriété de type List<ApplicationFunction_Application>. Classe ApplicationFunction_Application possédant deux propriétés, l'une de type Application et l'autre de type ApplicationFunction. Le but de la classe ApplicationFunction_Application est de définir une relation many-to-many entre Application et ApplicationFunction.

Dans le RecursivePropertyList de Application je mets:

myList.Add("ApplicationFunctions.Application");

Dans le RecursivePropertyList de ApplicationFunction je mets:

myList.Add("Applications.ApplicationFunction");

Dans le RecursivePropertyList de ApplicationFunction_Application je mets:

myList.Add("ApplicationFunction.Applications");

myList.Add("Application.ApplicationFunctions");

Mais, mon script ne cesse de boucle pour toujours et ne cesse jamais.

Voici le code utilisé par la fonction:

Tout d'abord, la fonction qui est appelée qui commence la chose:

public static EquatableList<PropertyState> FillPropertyStateList(System.Type myObjectType, ref EquatableList<PropertyState> myPropertyStateList) 
     { 
      List<string> myRecursivePropertyList = FillDefaultRecursivePropertyList(myObjectType); 
      return FillPropertyStateList(myObjectType, ref myPropertyStateList, string.Empty, string.Empty, myRecursivePropertyList); 
     } 

Ensuite, la fonction qui fait la viande du travail et que les appels lui-même de manière récursive pour générer la liste de propriétés pour tous les objets enfants.

public static EquatableList<PropertyState> FillPropertyStateList(System.Type myObjectType, ref EquatableList<PropertyState> myPropertyStateList, string myParentPrefix, string myObjectName, List<string> myRecursivePropertyList) 
     { 
      if (myPropertyStateList == null) 
      { 
       myPropertyStateList = new EquatableList<PropertyState>(); 
      } 
      if (string.IsNullOrEmpty(myParentPrefix)) 
      { 
       myParentPrefix = string.Empty; 
      } 
      else if (!myParentPrefix.EndsWith(".")) 
      { 
       myParentPrefix = myParentPrefix + "."; 
      } 
      if (string.IsNullOrEmpty(myObjectName)) 
      { 
       myObjectName = string.Empty; 
      } 
      else 
      { 
       myObjectName = myObjectName + "."; 
      } 

      foreach (System.Reflection.PropertyInfo info in myObjectType.GetProperties()) 
      { 
       if (info.PropertyType.BaseType == typeof(BOBase)) 
       { 
        if (!myRecursivePropertyList.Exists(delegate(string x) { return x.Equals(myObjectName + info.Name); })) 
        { 
         myPropertyStateList.Add(new PropertyState(myParentPrefix + myObjectName + info.Name, true, PropertyType.BOBase)); 
         List<string> myChildRecursivePropertyList = FillDefaultRecursivePropertyList(info.PropertyType); 
         myChildRecursivePropertyList.AddRange(myRecursivePropertyList.FindAll(delegate(string x) { return Regex.IsMatch(x, info.Name + ".*"); })); 
         FillPropertyStateList(info.PropertyType, ref myPropertyStateList, myParentPrefix + myObjectName, info.Name, myChildRecursivePropertyList); 
        } 
       } 
       else if (info.PropertyType.IsGenericType 
        && (info.PropertyType.BaseType.GetGenericTypeDefinition() == typeof(List<>) || info.PropertyType.BaseType.GetGenericTypeDefinition() == typeof(Library.EquatableList<>))) 
       { 
        if (!myRecursivePropertyList.Exists(delegate(string x) { return x.Equals(myObjectName + info.Name); })) 
        { 
         myPropertyStateList.Add(new PropertyState(myParentPrefix + myObjectName + info.Name, true, PropertyType.BOBaseCollection)); 
         List<string> myChildRecursivePropertyList = FillDefaultRecursivePropertyList(info.PropertyType.BaseType.GetGenericArguments()[0]); 
         myChildRecursivePropertyList.AddRange(myRecursivePropertyList.FindAll(delegate(string x) { return Regex.IsMatch(x, info.Name + ".*"); })); 
         FillPropertyStateList(info.PropertyType.BaseType.GetGenericArguments()[0], ref myPropertyStateList, myParentPrefix + myObjectName, info.Name, myChildRecursivePropertyList); 
        } 
       } 
       else 
       { 
        myPropertyStateList.Add(new PropertyState(myParentPrefix + myObjectName + info.Name, true, PropertyType.Standard)); 
       } 

      } 
      return myPropertyStateList; 
     } 

La fonction d'aide qui obtient la liste des propriétés récursive par défaut:

private static List<string> FillDefaultRecursivePropertyList(System.Type myObjectType) 
    { 
     List<string> myRecursivePropertyList = new List<string>(); 
     if (myObjectType.BaseType == typeof(BOBase)) 
     { 
      System.Reflection.PropertyInfo pi = myObjectType.GetProperty("RecursivePropertyList", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); 
      if (pi != null) 
      { 
       myRecursivePropertyList = (List<string>)pi.GetValue(null, null); 
      } 
     } 
     return myRecursivePropertyList; 
    } 

Toutes les idées sur ce que je fais mal?

+0

Pourquoi avez-vous besoin de cela? Mon premier instinct est qu'il doit y avoir une meilleure façon de réaliser tout ce que vous essayez d'accomplir, mais comme je ne sais pas ce que vous essayez d'accomplir, je ne peux rien suggérer. – Timwi

+0

Aussi, pourquoi n'utilisez-vous pas simplement le débogueur? Il peut vous dire exactement où se passe votre récursion infinie, et il vous permet de trouver où cela va mal. – Timwi

+0

J'ai besoin de la liste pour la raison suivante. Je veux pouvoir spécifier les propriétés d'un objet à instancier. Certaines propriétés de mon objet nécessitent un second déplacement vers la base de données pour obtenir plus de données, et parfois je n'ai pas besoin de ces données. Je voulais donc pouvoir définir les propriétés qui ne devraient pas être instanciées. Pour ce faire, j'ai besoin d'avoir une liste de propriétés avec une valeur bool flg qui détermine si cette propriété doit être "remplie" ou non. Espérons que cela a du sens? S'il y a une meilleure façon d'y parvenir, je suis tout ouïe. =) –

Répondre

0

Je n'ai pas encore creusé dans le code, mais avez-vous envisagé d'utiliser un attribut pour indiquer quelles propriétés sont récursives? Cela pourrait vous éviter le mal de tête d'avoir à maintenir la liste statique séparée des propriétés. Il semble que l'approche de la liste pourrait être sujette à des problèmes de synchronisation potentiellement difficiles.

ETA: Exemple de code:

Si je comprends correctement, quelque chose comme ça fonctionnerait probbaly pour un attribut niveau de la propriété. Il inclut une méthode d'assistance pour récupérer les propriétés marquées comme récursives du type donné, ce qui pourrait aider lors de la construction de l'arbre.

[AttributeUsage(AttributeTargets.Property)] 
public class RecursivePropertyAttribute 
    : Attribute 
{ 
    private static Dictionary<Type, List<PropertyInfo>> _Cache = new Dictionary<Type, List<PropertyInfo>>(); 

    public IEnumerable<PropertyInfo> GetRecursiveProperties(Type t) 
    { 
     // Check the cache for the type 
     if (!_Cache.ContainsKey(t)) 
     { 
      // Create the entry 
      _Cache.Add(t, new List<PropertyInfo>()); 

      // Add properties that have the attribute 
      foreach (PropertyInfo p in t.GetProperties()) 
      { 
       if (p.IsDefined(typeof(RecursivePropertyAttribute), true)) 
        _Cache[t].Add(p); 
      } 
     } 

     return _Cache[t]; 
    } 
} 
+0

Le problème avec ceci est qu'une propriété n'est pas déterminée pour être récursive dans sa propre classe. Par exemple, la propriété Vendor de Person n'est pas une propriété récursive en elle-même, mais la propriété Vendor des objets Person dans la propriété People de l'objet Vendor est récursive ... est-ce logique? Je dois donc pouvoir définir les propriétés récursives des ckasses "enfant" à partir de la classe d'instanciation parent. –

+0

Après avoir lu votre commentaire à la poste ci-dessus, je pense que je comprends un peu mieux votre problème. Si les propriétés «récursives» potentielles sont assez limitées, est-ce que le fait d'avoir des agents surchargés aurait du sens? Dans l'exemple que vous avez cité, aurait quelque chose comme Vendor() vs Vender (Person) vous permettre soit de pré-remplir la valeur de la propriété avec l'argument fourni, ou laisser vide pour être chargé paresseux au moment où il est nécessaire? – Steven

+0

A moins que je ne comprenne mal votre scénario (ce que je suis probablement), le fait que la récursivité de la propriété dépende de la chaîne d'événements ne serait-il pas en conflit avec la nature statique de la liste? Est-ce que cela pourrait être le problème? Ou la liste n'est-elle qu'une définition des propriétés récursives potentielles? – Steven

Questions connexes