C# 如何使用lambda表达式和匿名类型获取类型的属性名?
我尝试使用表达式树和匿名类型来实现以下功能 假设我有一门课:C# 如何使用lambda表达式和匿名类型获取类型的属性名?,c#,linq,lambda,petapoco,C#,Linq,Lambda,Petapoco,我尝试使用表达式树和匿名类型来实现以下功能 假设我有一门课: class Person { public string FirstName {get;set;} public string MiddleName {get;set;} public string LastName {get;set;} public DateTime DateOfBirth {get;set;} } 现在,我希望能够调用以下命令: string[] names = Foo<Perso
class Person
{
public string FirstName {get;set;}
public string MiddleName {get;set;}
public string LastName {get;set;}
public DateTime DateOfBirth {get;set;}
}
现在,我希望能够调用以下命令:
string[] names = Foo<Person>(x=> new { x.LastName, x.DateOfBirth });
string[]names=Foo(x=>new{x.LastName,x.DateOfBirth});
我希望名称包含两项,“姓氏”和“出生日期”
我试图以编译时安全的方式进行扩展,而不是编写字符串sql,这样我就可以指定要包含在sql中的属性/列的列表,而不是选择所有内容。我有一些相当大的实体,有些情况下,出于性能原因,我不想选择所有列。一页代码就是千言万语,下面是Microsoft如何做到这一点的:
///
///提供基于属性表达式提取属性信息的支持。
///
公共静态类属性支持
{
///
///从属性表达式中提取属性名称。
///
///包含表达式中指定的属性的对象类型。
///属性表达式(例如p=>p.PropertyName)
///属性的名称。
///如果值为null,则引发。
///表达式为时引发:
///不是一个
///不代表属性。
///或者,属性是静态的。
///
公共静态字符串ExtractPropertyName(表达式propertyExpression)
{
if(propertyExpression==null)
{
抛出新ArgumentNullException(“propertyExpression”);
}
var memberExpression=propertyExpression.Body作为memberExpression;
if(memberExpression==null)
{
抛出新的ArgumentException(Resources.PropertySupport_NotMemberAccessExpression_异常,“propertyExpression”);
}
var property=memberExpression.Member作为PropertyInfo;
if(属性==null)
{
抛出新的ArgumentException(Resources.PropertySupport_ExpressionNotProperty_异常,“propertyExpression”);
}
var getMethod=property.getMethod(true);
if(getMethod.IsStatic)
{
抛出新的ArgumentException(Resources.PropertySupport_StaticExpression_异常,“propertyExpression”);
}
返回memberExpression.Member.Name;
}
}
如果您想考虑属性,它会稍微复杂一些,但是接受表达式
并找出目标属性的名称的一般思路是相同的
更新:按原样,该方法只接受一个参数;我只是提供了一个指南。这个想法当然可以概括为:
public static string[] ExtractPropertyNames<T>(
Expression<Func<T, object>> propertyExpression)
公共静态字符串[]提取属性名称(
表达式属性(表达式)
此方法将接受一个表达式,该表达式接受一个T,并返回一个匿名类型,然后您可以对该类型进行反思。您可以用第二个类型参数替换
对象
,但这在这里并没有任何作用,因为您只想反映类型。我想您必须从System.Web.Mvc
汇编中反汇编Html.LabelFor(LabelExtensions.LabelFor
)的代码
例如,查看ExpressionHelper.GetExpressionText
至于用属性成员值替换成员名,你必须使用老式的反射。我很懒,所以这段代码只处理公共属性。但这应该是一个很好的基础,让你开始
public static string[] Foo<T>(Expression<Func<T, object>> func)
{
var properties = func.Body.Type.GetProperties();
return typeof(T).GetProperties()
.Where(p => properties.Any(x => p.Name == x.Name))
.Select(p =>
{
var attr = (ColumnAttribute) p.GetCustomAttributes(typeof(ColumnAttribute), true).FirstOrDefault();
return (attr != null ? attr.Name : p.Name);
}).ToArray();
}
公共静态字符串[]Foo(表达式func)
{
var properties=func.Body.Type.GetProperties();
返回typeof(T).GetProperties()
.Where(p=>properties.Any(x=>p.Name==x.Name))
.选择(p=>
{
var attr=(ColumnAttribute)p.GetCustomAttributes(typeof(ColumnAttribute),true.FirstOrDefault();
返回(attr!=null?attr.Name:p.Name);
}).ToArray();
}
请尝试以下尺寸:
public static string[] Foo<T, TResult>(Expression<Func<T, TResult>> func)
{
return typeof(TResult).GetProperties().Select(pi => pi.Name).ToArray();
}
这是因为第二个泛型参数是一种异常类型。这里给出的答案在仅选择单个属性或选择多个属性时有效。没有一个对两者都有效。在写我的答案时,by只适用于多个属性,其余的适用于单个属性 下面的代码考虑了这两种情况,也就是说,您可以使用它来选择单个属性和多个属性。请注意,我没有在这里添加任何心智检查,所以请随意添加您自己的
string[] Foo<T>(Expression<Func<Person, T>> func)
{
if (func.Body is NewExpression)
{
// expression selects multiple properties,
// OR, single property but as an anonymous object
// extract property names right from the expression itself
return (func.Body as NewExpression).Members.Select(m => m.Name).ToArray();
// Or, simply using reflection, as shown by Lukazoid
// return typeof(T).GetProperties().Select(p => p.Name).ToArray();
}
else
{
// expression selects only a single property of Person,
// and not as an anonymous object.
return new string[] { (func.Body as MemberExpression).Member.Name };
}
}
string[]Foo(表达式func)
{
if(funct.Body是NewExpression)
{
//表达式选择多个属性,
//或者,单个属性,但作为匿名对象
//从表达式本身提取属性名称权限
return(func.Body作为NewExpression.Members.Select(m=>m.Name).ToArray();
//或者,简单地使用反射,如Lukazoid所示
//返回typeof(T).GetProperties().Select(p=>p.Name).ToArray();
}
其他的
{
//表达式仅选择Person的单个属性,
//而不是作为匿名对象。
返回新字符串[]{(func.Body作为MemberExpression).Member.Name};
}
}
或者更简洁地说,使用三元运算符,一切都变成这样:
string[] Foo<T>(Expression<Func<Person, T>> func)
{
return (func.Body as NewExpression) != null
? typeof(T).GetProperties().Select(p => p.Name).ToArray()
: new string[] { (func.Body as MemberExpression).Member.Name };
}
string[]Foo(表达式func)
{
返回(func.Body作为NewExpression)!=null
?typeof(T).GetProperties().Select(p=>p.Name).ToArray()
:新字符串[]{(func.Body作为MemberExpression).Member.Name};
}
下载链接板文件:在线查看:
请随时指出我可能遗漏的任何内容。这不是只支持一个成员(即x=>x.LastName)吗?你是对的,它只支持单个成员。此外,单个成员不能作为匿名对象。看看我,它涵盖了两种情况,即单成员和多成员
string[] Foo<T>(Expression<Func<Person, T>> func)
{
if (func.Body is NewExpression)
{
// expression selects multiple properties,
// OR, single property but as an anonymous object
// extract property names right from the expression itself
return (func.Body as NewExpression).Members.Select(m => m.Name).ToArray();
// Or, simply using reflection, as shown by Lukazoid
// return typeof(T).GetProperties().Select(p => p.Name).ToArray();
}
else
{
// expression selects only a single property of Person,
// and not as an anonymous object.
return new string[] { (func.Body as MemberExpression).Member.Name };
}
}
string[] Foo<T>(Expression<Func<Person, T>> func)
{
return (func.Body as NewExpression) != null
? typeof(T).GetProperties().Select(p => p.Name).ToArray()
: new string[] { (func.Body as MemberExpression).Member.Name };
}