1
votes

Créer une chaîne via des appels de méthode récursifs

J'ai la structure de classe suivante (simplifiée):

MyObject1 object1_1 : instance1_instance2_object1_1
MyObject1 object2_1 : instance1_instance2_object2_1
MyObject1 object1_2 : instance1_instance3_object1_1
MyObject1 object2_2 : instance1_instance3_object1_2
MyObject1 object1_3 : instance1_object1_3
MyObject1 object2_3 : instance1_object2_3

Comme vous pouvez le voir, une instance de MyBaseType peut contenir une liste d'instances du même type ainsi qu'une liste de MyObject1 et MyObject2.

Une utilisation typique pour moi de ceci rendrait une structure comme indiqué ici:

MyBaseType instance1
|-> InstanceName = "instance1"
|
|-> MyBaseType instance2
|   |-> InstanceName = "instance2"
|   |
|   |-> MyObject1 object1_1
|   |   |-> SimpleName = "object1_1"
|   |-> MyObject2 object2_1
|   |   |-> SimpleName = "object2_1"
|
|-> MyBaseType instance3
|   |-> InstanceName = "instance3"
|   |
|   |-> MyObject1 object1_2
|   |   |-> SimpleName = "object1_2"
|   |-> MyObject2 object2_2
|   |   |-> SimpleName = "object2_1"
|
|-> MyObject1 object1_3
|   |-> SimpleName = "object1_3"
|-> MyObject2 object2_3
|   |-> SimpleName = "object2_3"

Visiblement, cette structure peut devenir assez complexe.

Ce que je dois faire est de plonger récursivement dans la liste MyBaseType , suivre toutes les valeurs de InstanceName au fur et à mesure que je vais ajouter la chaîne combinée avec le SimpleName de MyObject1 ou MyObject2 à la propriété Name de l'un ou l'autre des objets.

En suivant l'exemple de structure ci-dessus, les noms seraient:

public class MyBaseType
{
    public string InstanceName { get; set; }
    public List<MyBaseType> MyBaseTypeList = new List<MyBaseType>();
    public List<MyObject1> MyObject1List = new List<MyObject1>();
    public List<MyObject2> MyObject2List = new List<MyObject2>();
    // Other properties
}

public class MyObject1
{
    public string SimpleName { get; set; }
    public string Name { get; set; }
    // Other properties
}

public class MyObject2
{
    public string SimpleName { get; set; }
    public string Name { get; set; }
    // Other properties
}

J'ai du mal pour trouver un moyen d'itérer récursivement dans la List ET de garder une trace du nom en cours de construction.


7 commentaires

Je suis désolé, même si vous avez traversé pas mal de difficultés pour que cela ait un sens. Cela n'a pas de sens du moins pour moi. Quel est votre objectif final? Pourquoi avez-vous besoin que cela se produise de manière récursive? Un ensemble quoi?


Récursivement car puisqu'une instance de MyBaseType peut contenir une liste d'instances MyBaseType, vous passerez forcément par une récursivité pour atteindre une instance où ladite liste est vide


Eh bien, cela n'a pas besoin de se produire de manière récursive. Vous pouvez parcourir votre liste avec une boucle for . Aussi si vous voulez vous assurer qu'une propriété de type de base est définie. Vous pouvez forcer son instanciation via un constructeur si nécessaire. Je pense que vous êtes un peu confus avec les propriétés qui auto-référencent l'objet. Comme une classe de nœuds d'une liste chaînée. La réponse fournie est juste une boucle for mais cachée. Vous devez lire en quoi consiste linq.


Il est fort possible que vous ayez raison. Je vais regarder de plus près. J'ai supposé la récursivité car je ne sais pas combien de fois j'ajouterai une instance à la liste d'une autre instance. Pourrait être 100 fois


Hmm, je vois maintenant. Oui, une boucle for fera l'affaire. Afin de raccourcir votre code pour voir si toutes les propriétés sont instanciées. Je suggérerais d'utiliser LINQ docs.microsoft.com/en-us/dotnet/csharp/programming-guide/... . Plus précisément la fonction Any . Ce qui peut faire le chèque en une seule ligne. Sth comme ceci MyBaseType.MyBaseTypeList.Any (d => d.Name! = Null); Cela vérifiera toute la propriété Name de la liste si elle a une valeur. Désolé si vous obtenez des erreurs de compilation, je n'ai pas vérifié avec un IDE :)


Merci beaucoup ! Je vais l'examiner et j'espère avoir une solution bientôt.


De plus, la fonction Any que j'ai oublié de mentionner renvoie la valeur bool . J'espère que vous le faites fonctionner.


3 Réponses :


1
votes

Essayez quelque chose comme ceci:

public class MyBaseType
    {
        public string InstanceName { get; set; }
        public List<MyBaseType> MyBaseTypeList = new List<MyBaseType>();
        public List<MyObject1> MyObject1List = new List<MyObject1>();
        public List<MyObject2> MyObject2List = new List<MyObject2>();

        public string GetName()
        {
            return $"{InstanceName}-{string.Join('-',MyBaseTypeList.Select(q => q.GetName()))}";
        }
    }


2 commentaires

J'obtiens une erreur "Impossible de convertir de System.Generic.Collection.IEnumerable en chaîne" ... En outre, comment cette méthode parvient-elle à définir le nom des instances MyObject1 et MyObject2?


Géré pour le faire fonctionner, mais le résultat n'est qu'une concaténation de tous les InstanceName de l'instance particulière. Il n'y a pas de séparation par instance qui, si vous regardez la question, est ce dont j'ai besoin ...



1
votes

vous pouvez essayer d'appliquer le modèle de décorateur où vous passez votre identifiant de base.

Ajoutez cette méthode à votre classe MyBaseType;

public Dictionary<string,MyObject1> GenerateString(string bString)
    {
        if(bString != null) bString += "_";

        Dictionary<string, Object> dict = new Dictionary<string, Object>();
        if (MyBaseTypeList.DefaultIfEmpty() != null)
        {
             dict = this.MyBaseTypeList.Select(s => s.GenerateString(bString + InstanceName)).SelectMany(d => d).ToDictionary(e => e.Key, e => e.Value);
        }

        MyObject1List.ForEach(myObject => dict.Add(bString + InstanceName + "_" + myObject.SimpleName,myObject));
        MyObject2List.ForEach(myObject => dict.Add(bString + InstanceName + "_" + myObject.SimpleName,myObject));

        return dict;
    }

de cette façon, vous obtenez un dictionnaire de tous les objets avec leur chemin comme clé.

tout ce dont vous avez besoin est d'appeler la fonction dans l'objet de base avec un null comme paramètre. (instance1)


5 commentaires

J'aime ça, je vais le tester pour voir s'il correspond à ce dont j'ai besoin! (Notez que bien que MyObject1 et MyObject2 semblent identiques, ils ne le sont vraiment pas. Ils ont des propriétés très différentes autres que celles que j'écris réellement. Je l'ai spécifié je pense)


ont-ils tous les deux SimpleName en commun? si c'est le cas, vous pouvez les envelopper dans une classe qui contient juste SimpleName, de cette façon, vous pouvez enregistrer n'importe quelle classe.


Je vois l'idée oui, malheureusement, la structure de classe avec laquelle je travaille est plus complexe que ce que je peux montrer dans une question ici et je ne peux en aucun cas rejoindre les deux classes. Il y a redondance à cause de cela, mais c'est quelque chose que je sais comment trier à une date ultérieure.


Eh bien, nous pouvons toujours utiliser 2 classes complètement différentes, nous pouvons simplement utiliser Object comme wrapper dans le dictionnaire et identifier chaque objet par leurs identifiants respectifs


Code modifié pour que vous puissiez toujours utiliser n'importe quel objet pour votre liste



1
votes

Suite aux commentaires de panoskarajohn (que je remercie) et de tous ceux qui ont contribué, j'ai trouvé la solution suivante qui fait ce que j'attendais:

public void GenerateNames(string input)
{
    if (!IsEmpty(MyBaseTypeList))
    {
        foreach (MyBaseType mbt in MyBaseTypeList)
        {
            mbt.GenerateNames(input + "_" + mbt.InstanceName);
        }
    }
    else
    {
        foreach (MyObject1 mo1 in MyObject1List)
        {
            mo1.Name = input + "_" + mo1.SimpleName;
        }
        foreach (MyObject2 mo2 in MyObject2List)
        {
            mo2.Name = input + "_" + mo2.SimpleName;
        }
    }
}


0 commentaires