2009-02-16 10 views
0

Vous avez une question de réflexion complexe. Étant donné le code ci-dessous comment implémenteriez-vous le pseudo de sorte que donné une instance de Parent il énumérera sur les types Propriétés trouve des objets enfants avec une propriété du même type que Parent et définit la référence au p fourni. J'espère que cela a du sens. J'ai aussi besoin de cela pour travailler avec des listes génériques. Voir ci-dessous pour un exemple de graphe d'objet. Après avoir exécuté ceci, chaque instance de Person dans l'enfant Pet sera l'instance Parent.C# Réflexion et génériques

public class ChildSetter<Parent> 
    { 
     public void Set(Parent p) 
     { 

      //pseudo 
      //var parentName = p.GetType().Name; 
      //foreach (var property in p.Properties) 
      //{ 
      // if (!property.IsList) 
      // { 
      //  if (property.ContainsProperty(parentName)) 
      //   property.Properties[parentName] = p; 
      // } 
      // else 
      // { 
      //  if (property.ListType.ContainsProperty(parentName)) 
      //  { 
      //   foreach (var item in property) 
      //   { 
      //    item.Properties[parentName] = p; 
      //   } 
      //  } 
      // } 
      //} 
     } 
    } 

public class Person 
{ 
    public Pet Pet { get; set; } 
    public IList<Pet> Pets { get; set; } 

} 

public class Pet 
{ 
    public Person Person { get; set; } 
} 

Un exemple non générique de ce code est ci-dessous:

public void Set(Person p) 
    { 
     p.Pet.Person = p; 
     foreach (var pet in p.Pets) 
     { 
      pet.Person = p; 
     } 
    } 
+0

Cette question est liée à cette question: http://stackoverflow.com/questions/552736/child-tables-in-nhibernate – bleevo

Répondre

4

Je ne l'ai pas testé, mais que diriez-vous:

using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.Reflection; 

static class Program 
{ 
    static void Main() 
    { 
     ... 
    } 
    public static void SetParent<T>(T root) 
    { 
     foreach (PropertyInfo prop in typeof(T).GetProperties 
      (BindingFlags.Public | BindingFlags.Instance)) 
     { 
      if (!prop.CanRead) continue; 

      Type listType = null; 
      foreach (Type interfaceType in prop.PropertyType.GetInterfaces()) 
      { 
       if (interfaceType.IsGenericType && 
        interfaceType.GetGenericTypeDefinition() == typeof(IList<>)) 
       { // IList<T> detected 
        listType = interfaceType.GetGenericArguments()[0]; 
       } 
      } 

      List<PropertyInfo> propsToSet = new List<PropertyInfo>(); 
      foreach (PropertyInfo childProp in (listType ?? prop.PropertyType).GetProperties(
       BindingFlags.Public | BindingFlags.Instance)) 
      { 
       if (childProp.PropertyType == typeof(T)) propsToSet.Add(childProp); 
      } 

      if(propsToSet.Count == 0) continue; // nothing to do 
      if (listType == null) 
      { 
       object child = prop.GetValue(root, null); 
       if (child == null) continue; 
       foreach (PropertyInfo childProp in propsToSet) 
       { 
        childProp.SetValue(child, root, null); 
       } 
      } 
      else 
      { 
       IList list = (IList)prop.GetValue(root, null); 
       foreach (object child in list) 
       { 
        if (child == null) continue; 
        foreach (PropertyInfo childProp in propsToSet) 
        { 
         childProp.SetValue(child, root, null); 
        } 
       } 
      } 
     } 
    } 
} 
+0

Merci Marc Je vais vérifier – bleevo

+0

Il a probablement besoin d'une vérification nulle après avoir obtenu la liste (avant foreach), et peut-être aussi vérifier childProp.CanWrite lors du remplissage de propsToSet. –

+0

je devais changer cette ligne de interfaceType.GetGenericTypeDefinition() == typeof (IList <>)) à interfaceType.GetGenericTypeDefinition() == typeof (ICollection <>)) En dehors de cela, il fonctionne 100% merci tas. Je vais voir si c'est sain d'utiliser maintenant :) – bleevo