Reputation: 95
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
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
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
Reputation: 35146
Here are some useful references
Upvotes: 3