zmovahedi
zmovahedi

Reputation: 95

Get the full name of a nested property and its parents

How can I get the full name of a nested property by its parent using reflection in C#? I mean, for example we have this classes:

public class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public DateTime? DateOfBirth { get; set; }
    public Grade Grade { get; set; }
}

public class Grade
{
    public int GradeId { get; set; }
    public string GradeName { get; set; }
    public string Section { get; set; }
    public GradGroup GradGroup { get; set; }
}

public class GradGroup
{
    public int Id { get; set; }
    public string GroupName { get; set; }
}

I have "GradGroup" and Student as method parameters and want "Grade.GradeGroup" as output:

public string GetFullPropertyName(Type baseType, string propertyName)
    {
        // how to implement that??
    }

Call the method:

GetFullPropertyName(typeof(Student), "GradeGroup"); // Output is Grade.GradeGroup

Upvotes: 4

Views: 5332

Answers (3)

Oliver
Oliver

Reputation: 45109

Okay, I was just too late, but that's the solution that I came up with:

public static class TypeExtensions
{
    public static IEnumerable<string> GetFullPropertyNames(this Type type, string propertyName)
    {
        if (type == null)
            throw new ArgumentNullException(nameof(type));

        if (String.IsNullOrWhiteSpace(propertyName))
            throw new ArgumentNullException(nameof(propertyName));

        return GetFullPropertyNamesImpl(type, propertyName, new HashSet<Type>());
    }

    private static IEnumerable<string> GetFullPropertyNamesImpl(Type type, string propertyName, ICollection<Type> visitedTypes)
    {
        if (visitedTypes.Contains(type))
            yield break;

        visitedTypes.Add(type);

        var matchingProperty = type.GetProperty(propertyName);

        if (matchingProperty != null)
        {
            yield return matchingProperty.Name;
        }

        foreach (var property in type.GetProperties())
        {
            var matches = GetFullPropertyNamesImpl(property.PropertyType, propertyName, visitedTypes);

            foreach (var match in matches)
            {
                yield return $"{property.Name}.{match}";
            }
        }
    }
}

By using this class example:

public class GrandChild
{
    public int IntegerValue { get; set; }
    public string StringValue { get; set; }
    public bool BooleanValue { get; set; }
    public DateTime DateTimeValue { get; set; }
}

public class Child
{
    public GrandChild First { get; set; }
    public GrandChild Second { get; set; }
}

public class Parent
{
    public Child Mother { get; set; }
    public Child Father { get; set; }

}

You would call it

public class Program
{
    public static void Main()
    {
        var matches = typeof(Parent).GetFullPropertyNames("Ticks");

        foreach (var match in matches)
        {
            Console.WriteLine(match);
        }

        Console.ReadKey();
    }
}

And the output would be:

Mother.First.DateTimeValue.Ticks

Mother.First.DateTimeValue.TimeOfDay.Ticks

Upvotes: 2

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 250106

The property may not be unique as it might exist on several components so you should return an IEnumerable<string>. That being said you can traverse the property tree using GetProperties of Type:

public static IEnumerable<string> GetFullPropertyName(Type baseType, string propertyName)
{
    var prop = baseType.GetProperty(propertyName);
    if(prop != null)
    {
        return new[] { prop.Name };
    }
    else if(baseType.IsClass && baseType != typeof(string)) // Do not go into primitives (condition could be refined, this excludes all structs and strings)
    {
        return baseType
            .GetProperties()
            .SelectMany(p => GetFullPropertyName(p.PropertyType, propertyName), (p, v) => p.Name + "." + v);
    }
    return Enumerable.Empty<string>();
}

Upvotes: 10

Muhammad Hasan Khan
Muhammad Hasan Khan

Reputation: 35146

  • Use reflection to find all properties of a type
  • Use bread first search to find the nested property with given name
  • Concatenate the property names you found in the path with a "."

Here are some useful references

Upvotes: 3

Related Questions