Creating all objects using reflection of an object properties! - c#

Okay here is the scenario! I have a Person object which has an Address object. Person has a list of Addresses.
Now, I want to iterate through the properties of the Person and when I reach a List I want to create an object of the Address object. How can i do that?
Update:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
private List<Address> _addresses = new List<Address>();
public void AddAddress(Address address)
{
_addresses.Add(address);
address.Person = this;
}
public List<Address> Addresses
{
get { return _addresses; }
set { _addresses = value; }
}
}
var properties = item.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach(var property in properties)
{
var propertyType = property.PropertyType;
if (!propertyType.IsGenericType) continue;
var obj = Activator.CreateInstance(propertyType);
var genericType = obj.GetType().GetGenericTypeDefinition();
Console.WriteLine(obj.GetType().Name);
var type = property.GetType();
}
The above reflection code returns me a List but it is of type List. I want the Generic Type which is address.

Tony, if you have access to Address class then you could simply do this.
var properties = item.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
List<Address> retVal;
foreach (var property in properties)
{
var propertyType = property.PropertyType;
if (!propertyType.IsGenericType) continue;
retVal = property.GetValue(item, new object[] { }) as List<Address>;
if (retVal != null)
break;
}
//now you have your List<Address> in retVal

Related

C# how to recursively search object for objects of type x [duplicate]

This question already has answers here:
Recursively Get Properties & Child Properties Of A Class
(5 answers)
Closed 2 years ago.
I need to retrieve all objects of type X from a complex object.
public class Dog
{
public string Name {get;set;}
public int Age {get;set;}
public Owner Owner{get;set;}
public Kennel Kennel {get;set;}
}
public class Kennel
{
public string Name {get;set;}
public Address Address{get;set;}
public List<Dog> Dogs {get;set;}
}
public class Owner
{
public string Name {get;set;}
public string State {get;set;}
public Address Address{get;set;}
}
If I have an object composed of Dog, I would need to retrieve all address objects in all child objects.
If I understand you correctly, you might need to use Reflection to retrieve the Address objects:
public static class MyExtensions
{
public static List<Address> GetAddresses(this Dog dog)
{
var addresses = new List<Address>();
GetAddress(dog, ref addresses);
return addresses;
}
private static void GetAddress(object property, ref List<Address> addresses)
{
if (property == null)
{
return;
}
var props = property.GetType()
.GetProperties()
.Where(p => p.PropertyType.IsClass &&
!p.PropertyType.IsPrimitive)
.ToList();
foreach (var prop in props)
{
if (prop.PropertyType == typeof(Address))
{
var address = prop.GetValue(property) as Address;
addresses?.Add(address);
}
var next = prop.GetValue(obj: property);
// When property is a collection
if (next is IEnumerable collection)
{
foreach (var item in collection)
{
GetAddress(property: item,
addresses: ref addresses);
}
}
else
{
GetAddress(property: next,
addresses: ref addresses);
}
}
}
}
And usage example:
var dogs = new List<Dog>();
for (int i = 0; i < 5; i++)
{
var dog = new Dog
{
Name = $"Dog - {i}",
Age = 10,
Kennel = new Kennel
{
Address = new Address()
},
Kennels = new List<Kennel>
{
new Kennel
{
Address = new Address()
},
new Kennel
{
Address = new Address()
},
new Kennel()
{
Address = new Address()
}
},
Owner = new Owner
{
Address = new Address(),
Kennel = new Kennel
{
Address = new Address()
}
}
};
dogs.Add(dog);
}
var address = dogs.Select(dog => dog.GetAddresses());
Console.WriteLine(address.Sum(a => a.Count)); // will print 30
Please note that using Reflection could affect the performance of your application.
You don't need recursion here. Just SelectMany
Kennel home = getKennel();
List<Address> AllOwnerAddresses = home.Dogs.SelectMany(d = > d.Owner.Address).ToList();
Assuming that the structure is a tree
static IEnumerable<Address> GetAddresses(Dog dog)
{
yield return dog.Owner.Address;
yield return dog.Kennel.Address;
foreach (var addr in dog.Kennel.Dogs.SelectMany(dogC => GetAddresses(dogC)))
{
yield return addr;
}
}

Set Object null if all its properties are null in C#

I want to write a function which it turns every properies and child properties of an object. And if all properties of one property are null, then I will set that property as null. I will explain with one example.
For example, if both TeacherName and TeacherSurname are null then I want to set Teacher to null. Then, if ExamMark and ExamName and Teacher are null, then Exam will be null.
You can see json version of like my question from this link Json Version
public class Student
{
public string Name { get; set; }
public string Surname { get; set; }
public Address Address { get; set; }
public Exam Exam { get; set; }
}
public class Exam
{
public string ExamMark { get; set; }
public string ExamName { get; set; }
public Teacher Teacher { get; set; }
}
public class Teacher
{
public string TeacherName { get; set; }
public string TeacherSurname { get; set; }
}
public class Address
{
public string Country { get; set; }
public string City { get; set; }
}
I wrote this method. But this doing only first step. But I need recursive for child class. How can I convert this method to recursive?
public static object ConvertToNull(object obj)
{
Type objType = obj.GetType();
PropertyInfo[] properties = objType.GetProperties();
var mainClassProperties = properties.Where(p => p.PropertyType.Assembly == objType.Assembly);
foreach (var mainClassProperty in mainClassProperties)
{
object propValue = mainClassProperty.GetValue(obj, null);
var classAllProperties = propValue.GetType().GetProperties();
if (propValue.GetType().GetProperties().All(propertyInfo => propertyInfo.GetValue(propValue) == null))
{
mainClassProperty.SetValue(obj, null);
}
}
return obj;
}
What you're asking for is actually an anti-pattern. What this does is it propagates the requirement for tons of null checks in your code. Not only do you have to check if all properties are null, you also have to check if your object is null when you want to use it. Also reflection is very slow and if you're doing this often, you'll bog down your application.
You should look into the Null Object Pattern. It basically does what you want it to, and you remove all those pesky null checks:
public class Student
{
public string Name { get; set; }
public string Surname { get; set; }
public Address Address { get; set; }
public Exam Exam { get; set; }
public static Student NullStudent { get; } = new Student
{
Name = null,
Surname = null,
Address = Address.NullAddress,
Exam = Exam.NullExam,
}
}
You can do this for each object in your code that acts this way (you can see that I did it on your nested Address and Exam types as well) and then instead of doing this:
if (Student.EverythingIsNull) { Student = null }
if (Student is null) { //do null stuff }
You can do this:
if (item == Student.NullStudent) { //do null stuff }
This leads to clearer code, your intent stands out more, and you can specifically define in each object what constitutes as null.
using Generics and Reflection.
public T ConvertToNull<T>(T model) where T : class
{
if (model == null) return null;
Type type = model.GetType();
PropertyInfo[] properties = type.GetProperties();
var valueTypes = properties.Where(p => p.PropertyType.Assembly != type.Assembly);
var nonValueTypes = properties.Where(p => p.PropertyType.Assembly == type.Assembly);
foreach (var nonValueType in nonValueTypes)
nonValueType.SetValue(model, ConvertToNull(nonValueType.GetValue(model)));
if (valueTypes.All(z => z.GetValue(model) == null) && nonValueTypes.All(z => z.GetValue(model) == null))
return null;
else
return model;
}
Here you can call it
List<Student> students = new List<Student>();
Student student = new Student() { Name = "StudentName", Surname = "StudentSurname", Address = new Address() { City = "City", Country = "Country" }, Exam = new Exam() { ExamMark = "ExamMark", ExamName = "ExamName", Teacher = new Teacher() { TeacherName = "TeacherName", TeacherSurname = "TeacherSurname" } } };
Student student2 = new Student() { Name = "StudentName", Surname = "StudentSurname", Address = new Address(), Exam = new Exam() { ExamMark = "ExamMark", ExamName = "ExamName", Teacher = new Teacher() } };
students.Add(student);
students.Add(student2);
List<Student> results = new List<Student>();
foreach (var item in students)
{
var result = ConvertToNull(item);
results.Add(result);
}
Have a look at this The GetValueOrNull should work and do what you need, not tested with all possible use cases but it oculd be tweaked a little if doesn't work in all cases
public static bool IsSimpleType(Type type)
{
return
type.IsPrimitive ||
new Type[] {
typeof(Enum),
typeof(String),
typeof(Decimal),
typeof(DateTime),
typeof(DateTimeOffset),
typeof(TimeSpan),
typeof(Guid)
}.Contains(type) ||
Convert.GetTypeCode(type) != TypeCode.Object ||
(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>) && IsSimpleType(type.GetGenericArguments()[0]))
;
}
public object GetValueOrNull(object obj)
{
if (obj == null) return null;
Type objType = obj.GetType();
PropertyInfo[] properties = objType.GetProperties();
var simpleTypes = properties.Where(t => IsSimpleType(t.PropertyType));
var nonValueTypes = properties.Where(p => !simpleTypes.Contains(p));
foreach (var child in nonValueTypes)
{
child.SetValue(obj, GetValueOrNull(child.GetValue(obj)));
}
return simpleTypes.All(z => z.GetValue(obj) == null) && nonValueTypes.All(z => z.GetValue(obj) == null) ? null : obj;
}
call it as follows
var student = new Student { Address = new Address { }, Exam = new Exam { Teacher = new Teacher() } };
var test = GetValueOrNull(student);
hope it helps :)

Set property in nested object using reflection

I'm trying to set Address1 in obj1 using reflection and I can't figure out how to get a reference to the correct object. I'm not sure how to get a reference to the Address1 instance to pass into the first parameter of SetValue()
Round 1:
public class StackOverflowReflectionTest
{
[Fact]
public void SetDeepPropertyUsingReflection()
{
var breadCrumb = ".Addresses[0].Address1";
var obj1 = new Person()
{
Name = "Eric",
Addresses = new List<Address>()
{
new Address() {Address1 = "123 First Street"}
}
};
var newAddress1 = "123 Second Street";
var propNames = breadCrumb.Split(".");
for (var index = 0; index < propNames.Length; index++)
{
var propName = propNames[index];
if (propName.Contains("["))
{
var propNameToGet = propName.Substring(0, propName.IndexOf("[", StringComparison.Ordinal));
var prop = obj1.GetType().GetProperty(propNameToGet);
var leftBrace = propName.IndexOf("[", StringComparison.Ordinal);
var rightBrace = propName.IndexOf("]", StringComparison.Ordinal);
var position = int.Parse(propName.Substring(leftBrace + 1, rightBrace - leftBrace - 1));
var propNameToSet = propNames[index + 1];
var propToSet = prop.PropertyType.GetGenericArguments()[position].GetProperty(propNameToSet);
propToSet.SetValue(obj1, newAddress1);
}
else
{
//TODO: deal with different types
}
}
}
public class Person
{
public string Name { get; set; }
public IList<Address> Addresses { get; set; }
}
public class Address
{
public string Address1 { get; set; }
}
}
Round 2 based on Ed's feedback, still stuck on how to get the value on this line: var value = property.GetValue(obj, new object[] { indexPart });
public class StackOverflowReflectionTest
{
[Fact]
public void SetDeepPropertyUsingReflectionRound2()
{
var breadCrumb = "Addresses[0].Address1";
var obj1 = new Person()
{
Name = "Eric",
Addresses = new List<Address>()
{
new Address() {Address1 = "123 First Street"}
}
};
var newAddress1 = "123 Second Street";
SetPropertyValueByPath(obj1, breadCrumb, newAddress1);
}
public bool CrackPropertyName(string name, out string namePart, out object indexPart)
{
if (name.Contains("["))
{
namePart = name.Substring(0, name.IndexOf("[", StringComparison.Ordinal));
var leftBrace = name.IndexOf("[", StringComparison.Ordinal);
var rightBrace = name.IndexOf("]", StringComparison.Ordinal);
indexPart = name.Substring(leftBrace + 1, rightBrace - leftBrace - 1);
return true;
}
else
{
namePart = name;
indexPart = null;
return false;
}
}
public object GetPropertyValue(object obj, string name)
{
if(CrackPropertyName(name, out var namePart, out var indexPart))
{
var property = obj.GetType().GetProperty(namePart);
var value = property.GetValue(obj, new object[] { indexPart });
return value;
}
else
{
return obj.GetType().GetProperty(name);
}
}
public void SetPropertyValue(object obj, string name, object newValue)
{
var property = typeof(Address).GetProperty(name);
property.SetValue(obj, newValue);
}
public void SetPropertyValueByPath(object obj, string path, object newValue)
{
var pathSegments = path.Split(".");
if (pathSegments.Length == 1)
{
SetPropertyValue(obj, pathSegments[0], newValue);
}
else
{
//// If more than one remaining segment, recurse
var child = GetPropertyValue(obj, pathSegments[0]);
SetPropertyValueByPath(child, String.Join(".", pathSegments.Skip(1)), newValue);
}
}
public class Person
{
public string Name { get; set; }
public IList<Address> Addresses { get; set; }
}
public class Address
{
public string Address1 { get; set; }
}
}
Solution:
public class StackOverflowReflectionTest
{
[Fact]
public void SetDeepPropertyUsingReflectionSolution()
{
var breadCrumb = "Addresses[0].Address1";
var obj1 = new Person()
{
Name = "Eric",
Addresses = new List<Address>()
{
new Address() {Address1 = "123 First Street"}
}
};
var newAddress1 = "123 Second Street";
SetPropertyValueByPath(obj1, breadCrumb, newAddress1);
}
public bool CrackPropertyName(string name, out string namePart, out object indexPart)
{
if (name.Contains("["))
{
namePart = name.Substring(0, name.IndexOf("[", StringComparison.Ordinal));
var leftBrace = name.IndexOf("[", StringComparison.Ordinal);
var rightBrace = name.IndexOf("]", StringComparison.Ordinal);
indexPart = name.Substring(leftBrace + 1, rightBrace - leftBrace - 1);
return true;
}
else
{
namePart = name;
indexPart = null;
return false;
}
}
public object GetPropertyValue(object obj, string name)
{
if(CrackPropertyName(name, out var namePart, out var indexPart))
{
var property = obj.GetType().GetProperty(namePart);
var list = property.GetValue(obj);
var value = list.GetType().GetProperty("Item").GetValue(list, new object[] { int.Parse(indexPart.ToString()) });
return value;
}
else
{
return obj.GetType().GetProperty(namePart);
}
}
public void SetPropertyValue(object obj, string name, object newValue)
{
var property = typeof(Address).GetProperty(name);
property.SetValue(obj, newValue);
}
public void SetPropertyValueByPath(object obj, string path, object newValue)
{
var pathSegments = path.Split(".");
if (pathSegments.Length == 1)
{
SetPropertyValue(obj, pathSegments[0], newValue);
}
else
{
//// If more than one remaining segment, recurse
var child = GetPropertyValue(obj, pathSegments[0]);
SetPropertyValueByPath(child, String.Join(".", pathSegments.Skip(1)), newValue);
}
}
public class Person
{
public string Name { get; set; }
public IList<Address> Addresses { get; set; }
}
public class Address
{
public string Address1 { get; set; }
}
}
Type.GetGenericArguments() doesn't do anything like what I think you're assuming.
What you want here is recursion. Given ”Foo.Bar[1].Baz”, get Foo. Get Bar[1] from that. Get the PropertyInfo from Baz from its parent, use that to set the value of the Baz property of the Bar[1] property of Foo.
To break it down:
Write a method that "cracks" a property name and uses out parameters to return both the name part and the index value part: "IndexedProperty[1]" goes in; "IndexedProperty" and integer 1 come out. "FooBar" goes in, "FooBar" and null come out. It returns true if there's an indexer, false if not.
bool CrackPropertyName(string name, out string namePart, out object indexPart)
Write a method that takes an object, and a string "PropertyName" or "IndexedPropety[0]" (not a path -- no dot) and returns the value of that property on that object. It uses CrackPropertyName() to simplify its job.
object GetPropertyValue(object obj, string name)
Write a method that sets a property value by name (not by path, just by name). Again, it uses CrackPropertyName() to simplify its job.
void SetPropertyValue(object obj, string name, object newValue)
A recursive method using the above:
void SetPropertyValueByPath(object obj, string path, object newvalue)
{
var pathSegments = /* split path on '.' */;
if (pathSegments.Length == 1)
{
SetPropertyValue(obj, pathSegments[0], newValue);
}
else
{
// If more than one remaining segment, recurse
var child = GetNamedPropertyvalue(obj, pathSegments[0]);
return SetPropertyValueByPath(obj, String.Join(".", pathSegments.Skip(1)), newValue);
}
}
These methods are all pretty trivial. Since you're using reflection anyway, you may as well go whole hog and write one non-generic method that sets any property of anything.
Here is the quick and dirty I put together in LINQPad that changes the Address1 property of the object you have defined.
void Main()
{
var obj1 = new Person()
{
Name = "Eric",
Addresses = new List<Address>()
{
new Address() {Address1 = "123 First Street"}
}
};
var index = 0;
var addressList = typeof(Person)
.GetProperty("Addresses")
.GetValue(obj1);
var address = addressList.GetType()
.GetProperty("Item")
.GetValue(addressList, new object[]{index});
address.GetType()
.GetProperty("Address1")
.SetValue(address,"321 Fake Street");
Console.WriteLine(obj1.Addresses[index].Address1); // Outputs 321 Fake Street
}
// Define other methods and classes here
public class Person
{
public string Name { get; set; }
public IList<Address> Addresses { get; set; }
}
public class Address
{
public string Address1 { get; set; }
}
If you want to use reflection to get the value of the Addresses property from an instance of Person you would do this:
var myPerson = new Person()
{
Name = "Eric",
Addresses = new List<Address>()
{
new Address() {Address1 = "123 First Street"}
}
};
var property = typeof(Person).GetProperty("Addresses");
var addresses = (IList<Address>) property.GetValue(myPerson );
First you're finding the property - an instance of PropertyInfo - which belongs to the Person type. Then you're retrieving the value of that property for a specific instance of Person, myPerson.
addresses is an IList<Address> so there's not much use in using reflection to get a particular Address from the list. But if for some reason you wanted to:
private Address GetAddressAtIndex(IList<Address> addresses, int index)
{
var property = typeof(IList<Address>).GetProperty("Item");
var address = (Address) property.GetValue(addresses, new object []{index});
return address;
}
This is essentially the same as the first example, except that in this case the property (Item) requires an index. So we use the overload of GetValue that accepts one or more indexes.
Now you've got an instance of Address. I'm doing each of these in separate steps because they are all separate steps. There's no one step that will perform the entire operation.
If you have an instance of an address and you want to use reflection to set the Address1 property:
private void SetAddress1OnAddress(Address address, string address1Value)
{
var property = typeof(Address).GetProperty("Address1");
property.SetValue(address, address1Value);
}
Very similar. You're first retrieving the Address1 property and then calling its SetValue method to set the value on a specific instance if Address.

Dynamically build an object from a strongly typed class using C#?

Currently, am adding the properties and values to the object manually like this example and sending to Dapper.SimpleCRUD to fetch data from Dapper Orm. This is the desired output I would like to achieve.
object whereCriteria = null;
whereCriteria = new
{
CountryId = 2,
CountryName = "Anywhere on Earth",
CountryCode = "AOE",
IsActive = true
};
The following class should build the object in the above mentioned format and return the ready-made object.
public static class WhereClauseBuilder
{
public static object BuildWhereClause(object model)
{
object whereObject = null;
var properties = GetProperties(model);
foreach (var property in properties)
{
var value = GetValue(property, model);
//Want to whereObject according to the property and value. Need help in this part!!!
}
return whereObject;
}
private static object GetValue(PropertyInfo property, object model)
{
return property.GetValue(model);
}
private static IEnumerable<PropertyInfo> GetProperties(object model)
{
return model.GetType().GetProperties();
}
}
This function WhereClauseBuilder.BuildWhereClause(object model) should return the object in expected format (mentiond above). Here is the implementation of how I would like to use.
public sealed class CountryModel
{
public int CountryId { get; set; }
public string CountryName { get; set; }
public string CountryCode { get; set; }
public bool IsActive { get; set; }
}
public class WhereClauseClass
{
public WhereClauseClass()
{
var model = new CountryModel()
{
CountryCode = "AOE",
CountryId = 2,
CountryName = "Anywhere on Earth",
IsActive = true
};
//Currently, won't return the correct object because the implementation is missing.
var whereClauseObject = WhereClauseBuilder.BuildWhereClause(model);
}
}
Maybe something like that:
private const string CodeTemplate = #"
namespace XXXX
{
public class Surrogate
{
##code##
}
}";
public static Type CreateSurrogate(IEnumerable<PropertyInfo> properties)
{
var compiler = new CSharpCodeProvider();
var compilerParameters = new CompilerParameters { GenerateInMemory = true };
foreach (var item in AppDomain.CurrentDomain.GetAssemblies().Where(x => !x.IsDynamic))
{
compilerParameters.ReferencedAssemblies.Add(item.Location);
}
var propertiesCode =
string.join("\n\n", from pi in properties
select "public " + pi.PropertyType.Name + " " + pi.Name + " { get; set; }");
var source = CodeTemplate.Replace("##code##", propertiesCode);
var compilerResult = compiler.CompileAssemblyFromSource(compilerParameters, source);
if (compilerResult.Errors.HasErrors)
{
throw new InvalidOperationException(string.Format("Surrogate compilation error: {0}", string.Join("\n", compilerResult.Errors.Cast<CompilerError>())));
}
return compilerResult.CompiledAssembly.GetTypes().First(x => x.Name == "Surrogate");
}
And now use it:
public static object BuildWhereClause(object model)
{
var properties = GetProperties(model);
var surrogateType = CreateSurrogate(properties);
var result = Activator.CreateInstance(surrogateType);
foreach (var property in properties)
{
var value = GetValue(property, model);
var targetProperty = surrogateType.GetProperty(property.Name);
targetProperty.SetValue(result, value, null);
}
return result;
}
I didn't compile that. It's only written here. Maybe there are some errors. :-)
EDIT:
To use ExpandoObject you can try this:
public static object BuildWhereClause(object model)
{
var properties = GetProperties(model);
var result = (IDictionary<string, object>)new ExpandoObject();
foreach (var property in properties)
{
var value = GetValue(property, model);
result.Add(property.Name, value);
}
return result;
}
But I don't know whether this will work for you.

Get some properties from an object and nested object

I'd like return an object (ExpandoObject) with only the fields and nested fields received by the method.
var fieldsToGet = new List<string> { "FirstName", "Id"};
When I do this :
.Select(x => Helpers.FilteringProperties(x, fieldsToGet))
I receive an object with this two values, that's work.
I receive an object with FirstName and Id
Now I'd like return some properties of the nested object :
var fieldsToGet = new List<string> { "FirstName", "Id", "Language.Name"};
I'd like receive these properties :
FirstName, Id and Language.Name
The code below works but I'd like stay generic enough and be able to manage the nested.
How can I do this generic, managed the nested object ?
Thanks,
The current code :
public static object FilteringProperties(object employee, List<string> fields)
{
if (!fields.Any())
return employee;
else
{
ExpandoObject result = new ExpandoObject();
foreach (var field in fields)
{
var fieldValue = employee.GetType()
.GetProperty(field, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance)
.GetValue(employee, null);
((IDictionary<String, Object>)result).Add(field, fieldValue);
}
return result;
}
}
Sample classes :
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Language Language { get; set; }
public int LanguageId { get; set; }
}
public class Language
{
public int Id { get; set; }
public string Code { get; set; }
public string Name { get; set; }
}
I suppose you could do a split on the "."-character, get the Property with that name, and then get its value by calling your own function recursively.
Something like this (pseudo-code, can be a lot better)
if (field.Contains(".")) {
var parts = field.Split('.');
var fieldName = parts[0];
List<string> toGet = new List<string>();
toGet.Add(parts[1]); // this now contains everything after the "."
var fieldValue = employee.GetType()
.GetProperty(fieldName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance)
.GetValue(employee, null);
((IDictionary<String, Object>)result).Add(field, FilteringProperties(fieldValue, toGet)
}
Using a recursive approach. I'm sure it can be improved.
public static object FilteringProperties(object employee, List<string> fields)
{
if (!fields.Any())
return employee;
else
{
ExpandoObject result = new ExpandoObject();
foreach (var field in fields)
{
object fieldValue = null;
Regex regex = new Regex("(\\w+)\\.(\\w+)");
Match match = regex.Match(field);
if (match.Success)
{
string className = match.Groups[1].Value;
string propertyName = match.Groups[2].Value;
var o = FilteringProperties(employee.GetType().GetProperty(className).GetValue(employee, null), new List<string>() {propertyName});
var entry = (IDictionary<string, object>) o;
fieldValue = entry[propertyName];
}
if(fieldValue == null)
fieldValue = employee.GetType()
.GetProperty(field, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance)
.GetValue(employee, null);
((IDictionary<String, Object>)result).Add(field, fieldValue);
}
return result;
}
}
Something like this seems to work for me -
public static ExpandoObject CreateObject(object parent, List<string> fields)
{
var expando = new ExpandoObject();
var ret = (IDictionary<string,object>)expando;
foreach (var property in fields)
{
//split to determine if we are a nested property.
List<string> properties = property.Split('.').ToList();
if (properties.Count() > 1)
{
//get our 'childs' children - ignoring the first item
var grandChildren = properties.Skip(1);
//copy this child object and use it to pass back into this method recusivly - thus creating our nested structure
var child = parent.GetType().GetProperty(properties[0]).GetValue(parent, null);
//passing in the child object and then its children - which are grandchildren from our parent.
ret.Add(properties[0], CreateObject(child, grandChildren.ToList()));
}
else //no nested properties just assign the property
ret.Add(property, parent.GetType().GetProperty(property).GetValue(parent));
}
return expando;
}
Thanks to Marc - guru from this site - I came up with the following approach:
public static object GetFlattenPropertyValue(this object source, string flattenPropertyName) {
var expression = source.GetType().CreatePropertyExpression(flattenPropertyName);
if (expression != null) {
var getter = expression.Compile();
return getter.DynamicInvoke(source);
}
return null;
}
public static LambdaExpression CreatePropertyExpression(this Type type, string flattenPropertyName) {
if (flattenPropertyName == null) {
return null;
}
var param = Expression.Parameter(type, "x");
Expression body = param;
foreach (var member in flattenPropertyName.Split('.')) {
body = Expression.PropertyOrField(body, member);
}
return Expression.Lambda(body, param);
}

Categories

Resources