I want to create a dictionary that has all of the public properties of an object mapped to the plain string property name. For example, the following "Person" class should return the following dictionary. I think I want to walk the object tree with the .GetProperties()
method, but I am having trouble with where to go from there.
Code:
public class Person
{
public string FirstName;
public string LastName;
public Address Addr;
}
public class Address
{
public string Country;
public City City;
}
public class City
{
public string ZipCode;
public string Street;
}
Dictionary Result:
Property Name | Full Path |
---|---|
FirstName |
FirstName |
LastName |
LastName |
Country |
Addr.Country |
ZipCode |
Addr.City.ZipCode |
Street |
Addr.City.Street |
CodePudding user response:
Although I couldn't figure out why you need to do it, you can use reflection to get all data you need:
void PropertyToDictionary()
{
Person person = new()
{
FirstName = "Johnny",
LastName = "Depp",
Addr = new()
{
City = new()
{
Street = "Street",
ZipCode = "12345"
}
}
};
var dic =new Dictionary<string, string>();
person.GetType()
.GetProperties()
.ToList()
.ForEach(p =>
{
if (p.Name == "Addr")
{
p.GetValue(person)
.GetType()
.GetProperties()
.ToList()
.ForEach(pp =>
{
if (pp.Name == "City")
{
pp.GetValue(person.Addr)
.GetType()
.GetProperties()
.ToList()
.ForEach(ppc =>
{
dic.Add(ppc.Name, $"{p.Name}.{pp.Name}.{ppc.Name}");
});
}
else
{
dic.Add(pp.Name, $"{p.Name}.{pp.Name}");
}
});
}
else
{
dic.Add(p.Name,p.Name);
}
});
foreach (var item in dic)
{
Console.WriteLine(item.Key "-----" item.Value);
}
}
Output:
CodePudding user response:
Apologies that I did not do a good job explaining my problem. I wanted to keep it high level from the actual core of the problem, but I think that ended up being more confusing.
Essentially, I have a web project that makes requests to search, sort, etc. on Database Entities. The requests only contain a single string as the property that should be used and then the type of request. That property code is at the top-level or nested. So, I needed to build out a way to get the possible top-level and nested properties that I can use and map that to just the simple name. In the end, just a dynamic dictionary with all public top-level properties and nested properties.
Here is how I ended up solving it:
/// <summary>
/// This method will populate the <paramref name="propertiesDictionary"/> with keys of all of the public property and nested
/// public properties. This is useful for mapping search, sort, etc. requests with the request property to the fully pathed
/// with the object property name. The values of the dictionary can then be used in linq queries to pull the data from the entities.
/// Important notes:
/// 1. This will only use the top most level property name if there are multiple properties with the same name.
/// 2. This will not handle nested objects of the same type.
/// 3. It requires all objects to reside in the same namespace. This is needed to ignore properties on strings, Lists, etc. However, this means only objects in that namespace will be used.
/// </summary>
/// <param name="objectType">The type of the object that will be pulled from</param>
/// <param name="propertiesDictionary">The dictionary that will be populated with the plain string names as the keys and the full pathed property has the value</param>
/// <param name="objectNameSpace">The namespace of the properties</param>
/// <param name="prefix">Prefix used in the recursive call to fill out the full path. THIS SHOULD BE EMPTY ON THE FIRST CALL</param>
/// <param name="topLevelObject">The top level object that we are using. THIS SHOULD BE NULL ON THE FIRST CALL</param>
/// <param name="recurssionIteration">The current iteration of recursive which is used to bail to avoid a stack-overflow. THIS SHOULD BE ZERO ON THE FIRST CALL</param>
private static void GetPublicPropertiesAndNestedPropertiesRecursively( Type objectType, IDictionary<string, string> propertiesDictionary, string objectNameSpace, string prefix = "", Type topLevelObject = null, int recurssionIteration = 0 )
{
// First, check to make sure that we didn't hit the recursion max
if ( recurssionIteration > 8 )
{
return;
}
// If this is not the first call, bail out if this is the same object. This would cause an infinite loop if not.
// If this is the first call, set the top level object.
if ( topLevelObject == null )
{
topLevelObject = objectType;
}
else if ( objectType == topLevelObject )
{
return;
}
// Get all the public properties and return if there is no or th
var currentProperties = objectType.GetProperties();
if ( objectType.GetProperties().Length < 1 || objectType.Namespace == null || !objectType.Namespace.StartsWith( objectNameSpace ) )
{
return;
}
// Add all of the properties that currently don't exist
foreach ( var currentProperty in currentProperties.Where( currentProperty => !propertiesDictionary.ContainsKey( currentProperty.Name.ToLower() ) ) )
{
propertiesDictionary.Add( currentProperty.Name.ToLower(), $"{prefix}{currentProperty.Name}".ToLower() );
}
// Recursively get all of the nested properties
foreach ( var propertyInfo in currentProperties )
{
GetPublicPropertiesAndNestedPropertiesRecursively( propertyInfo.PropertyType, propertiesDictionary, objectNameSpace, $"{propertyInfo.Name}.", topLevelObject, recurssionIteration );
}