我想返回一个只包含方法接收的字段和嵌套字段的对象(ExpandoObject
)。
var fieldsToGet = new List<string> { "FirstName", "Id"};
当我这样做时:
.Select(x => Helpers.FilteringProperties(x, fieldsToGet))
我收到一个带有这两个值的对象,这是有效的。
我收到了FirstName
和Id
现在我想返回嵌套对象的一些属性:
var fieldsToGet = new List<string> { "FirstName", "Id", "Language.Name"};
我想收到这些属性:
FirstName
,Id
和Language.Name
下面的代码有效,但我希望保持足够的通用性并能够管理嵌套。
如何执行此通用操作,管理嵌套对象?
谢谢,
当前代码:
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;
}
}
示例类:
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; }
}
答案 0 :(得分:1)
我想你可以对“。” - 字符进行拆分,获取具有该名称的Property,然后通过递归调用自己的函数来获取它的值。
像这样(伪代码,可以更好)
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)
}
答案 1 :(得分:0)
使用递归方法。我相信它可以改进。
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;
}
}
答案 2 :(得分:0)
这样的事似乎对我有用 -
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;
}
答案 3 :(得分:0)
感谢Marc - guru来自这个网站 - 我提出了以下方法:
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);
}