-1

I have a problem where I receive objects from an external api, and deserialized into c# objects in my system. These objects are logged on my system, therefore I need to be able to sanitize them.

A good example of a object structure that I could be dealing with could be this one:

var person = new {
       Name = "Filip",
       friends = new string[] { "Lorem ipsum @exampel.com för s",                                                                          
                                "Ange mailasasa", "Ange mailadress på                                
                                  formen namn@exampel.com för s",
                                "Some random text",
                                "Ange mailadress på formen" },
       innerObj = new  { s = new List<string>() {
                                "nge mailadress på formen na.com för s",  
                                "Ange mailadress på formen amn@exampel.com för sökande: 920294-1801",
                                "Ange mailadress på formen namn@exampel.com fö"},
                          anotherField = "nldsa",
                        },
       Age = 24
};

Speficially, I need to detect the substring "920294-1801", the regex-part of this problem is not what I want to ask about.

I would like to know the best way to look into a object, look at all it's fields that are string type, also the ones that are nested in other datastructures. In the example here, I need to look into the "InnerObj" and then into the list elements inside that list.

So is there any way that I can receive ALL nested string fields inside a object, and iterate through them?

EDIT: I probably should clarify that I need a approach that can work for object of different internal structure. This means that it should not just work this example object, but many differnt generic objects of differing structure

EDIT: It has been suggested that this question has been asked before, however it has not, since none of the other questions are looking for a general method to get all fields (+ nested fields) from objects of differing structure

n00bster
  • 379
  • 4
  • 12
  • Are you doing this to substitute all instances of a string? – tymtam Dec 13 '20 at 01:40
  • Does this answer your question? [C#: How to get all public (both get and set) string properties of a type](https://stackoverflow.com/questions/824802/c-how-to-get-all-public-both-get-and-set-string-properties-of-a-type) – tymtam Dec 13 '20 at 01:44
  • No, this question does not speak about getting nested values – n00bster Dec 13 '20 at 12:04
  • depends what you mean tymfam, any occurence of 10 consecutive that I can find anywhere in the object sgould be replaced. However this is not what the question is about, I just want to iterate through all fields, including nested ones – n00bster Dec 13 '20 at 12:06

2 Answers2

0

I see 3 options:

  • If you know the structure of the object then write code that checks all of them. Even for a large object this shouldn't take to long. If a new property is added then the method would have to be extended.
  • Serialize the object to, for example JSON, do the regex and deserialise. Risk: you may break the object if your substitution changes a property name, etc.
  • Use Reflection to find all string properties. Example how to do it is at: C#: How to get all public (both get and set) string properties of a type
tymtam
  • 31,798
  • 8
  • 86
  • 126
  • - The whole idea of the problem is that I dont know the structure of the object - serilalizing would probably be too big an operation, and too risky, I need to be certain that it sdoes not break - I'm currently looking at reflection, but my problem is about looking in the nested fields, the question you linked does not contain a solution for that – n00bster Dec 13 '20 at 11:57
0

To get you started, this code will add all properties of the object into an ArrayList, utilizing Type quite frequently to know how to parse each entity (like a string, array, or list) and add it to the ArrayList:

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

var person = new
{
    Name = "Filip",
    friends = new string[] { "Lorem ipsum @exampel.com för s",
                             "Ange mailasasa", "Ange mailadress på formen namn@exampel.com för s",
                             "Some random text",
                             "Ange mailadress på formen" },
    innerObj = new 
    { s = new List<string>()
        {
            "nge mailadress på formen na.com för s",
            "Ange mailadress på formen namn@exampel.com för sökande: 920294-1801",
            "Ange mailadress på formen namn@exampel.com fö"
        },
        anotherField = "nldsa",
    },
        Age = 24
};
    
var properties = GetProperties(person);
ArrayList propLst = new ArrayList();
    
foreach (var p in properties)
{
    string name = p.Name;
    var value = p.GetValue(person, null);
    Type valueType = value.GetType();
    if (valueType.IsArray) {
        string[] arr = ((IEnumerable)value).Cast<object>()
                       .Select(x => x.ToString())
                       .ToArray();
        for (int i = 0; i < arr.Length; i++)
        {
            propLst.Add(arr[i]);
        }
    }
    else if (value is string || value is int) {
        propLst.Add(value);
    }
    else {   // If not array or string or integer, it must be the (nested) object with a list inside
        var nestedObjectsProperties = p.PropertyType.GetProperties();
        foreach (var prop in nestedObjectsProperties) {
            var listObject = prop.GetValue(value, null);
            Type valueTypeInNestedObj = listObject.GetType();
            if (valueTypeInNestedObj.IsGenericType) {
                var collection = ((IEnumerable)listObject).Cast<object>().ToList();
                foreach (var val in collection) {
                   propLst.Add(val);   
                }
            }
            else {  // If not list, must be "anotherField"
                propLst.Add(listObject);
            }
        }
    } 
}
    
PrintValues(propLst);

private PropertyInfo[] GetProperties(object obj)
{
    return obj.GetType().GetProperties();
}

private void PrintValues(IEnumerable myList) {
  foreach (Object obj in myList)
     Console.WriteLine(obj);
}

From there, you can detect that substring using a regex or the Split() method for the text after the colon, all by iterating through the strings in the ArrayList.

Max Voisard
  • 1,685
  • 1
  • 8
  • 18
  • this looks very interesting, will just test it out – n00bster Dec 13 '20 at 12:03
  • Hmm, no i'm afraid. This code only works for the example object shown. I need an approach that can get me ALL nested fields of objects with different structure – n00bster Dec 13 '20 at 12:13
  • I know this only works for the example you gave, but you can tweak the code a little to adjust for the objects you receive based on each property's `Type`. I would assume you are receiving a consistent structure for the objects, since they come from an API. Can you give more examples of objects (which I presume are JSON) you get from the API? – Max Voisard Dec 14 '20 at 03:15