访问C#属性名称或属性

14

我想从一个类实例自动生成SQL语句。该方法应该看起来像Update(object[] Properties, object PrimaryKeyProperty)。该方法是实例的一部分(类,基础方法-适用于任何子项)。属性数组是一组将用于更新语句中的类属性数组。属性名等于表字段名。

问题是我无法获取属性名称。

是否有任何选项可以在类实例内获取属性名称? 示例:

public class MyClass {
public int iMyProperty { get; set; }
public string cMyProperty2 { get; set; }
{

main() {
 MyClass _main = new MyClass();

_main.iMyProperty.*PropertyName* // should return string "iMyProperty"

{

我知道PropertyInfo,但不知道如何从GetProperties()数组中获取属性的ID。

有什么建议吗?

7个回答

28

我刚刚为我们的用户组上周二的lambda演示编写了这个实现

  • 您可以执行

    MembersOf<Animal>.GetName(x => x.Status)

  • 或者

    var a = new Animal() a.MemberName(x => x.Status)

代码如下:

public static class MembersOf<T> {
    public static string GetName<R>(Expression<Func<T,R>> expr) {
        var node = expr.Body as MemberExpression;
        if (object.ReferenceEquals(null, node)) 
            throw new InvalidOperationException("Expression must be of member access");
        return node.Member.Name;
    }
}

@GeorgeMauer 为什么不用 MembersOf.GetName<T>(Expression<Func<T,Object>> expr) 替换 MembersOf<T>.GetName<R>(Expression<Func<T,R>> expr),这样更简单,而且你不需要一个特定的 R 类型(即使它在编译时被推断出来)。 - Yves M.
@YvesM. 那会有什么优势呢? - George Mauer
@GeorgeMauer 类型T和R是分开的:MembersOf<T>GetName<R>而不是GetName<T,R>。这样做只是为了隔离类型R,以便可以推断出R。问题是当我需要在另一个函数中使用MembersOf时,我必须指定T和R,而无法将它们分开。例如:public string MyFunction<T,R>(Expression<Func<T, R>> expr){return new MembersOf<T>().GetName<R>()}。T和R不再分开,当使用MyFunction<T,R>时,R无法被推断。但是,如果您将R替换为Object,则无需进行任何技巧来方便推断。 - Yves M.
@GeorgeMauer,语义上更准确的是返回一个对象。没有人关心类型R,我们只需要表达式返回任何东西。 - Yves M.
关于类型推断的观点很好,但我不太倾向于同意后者。没有约束条件的<T,R>表示“任何T和任何R”,而<T,Object>可能意味着“任何T和一个向下转型/装箱对象”。您的观点可能通过<T,dynamic>签名更好地传达。无论如何,这些都是非常小的考虑因素 - 我甚至可能不会在代码审查中提到它们。 - George Mauer
显示剩余3条评论

10

我在这篇文章中找到了一个完美的解决方案。

public static string GetPropertyName<T>(Expression<Func<T>> propertyExpression)
{
   return (propertyExpression.Body as MemberExpression).Member.Name;
}

然后是用法:

var propertyName = GetPropertyName(
() => myObject.AProperty); // returns "AProperty"

运行得非常好


6
你可以像这样做:

你可以像这样去做:

Type t = someInstance.getType();

foreach (MemberInfo mi in t.GetMembers())
{
    if (mi.MemberType == MemberTypes.Property)
    {
        Console.WriteLine(mi.Name);
    }
}

获取instance类型的所有属性名称。


1
他不需要所有的属性名称,只需要特定的一些。 - George Mauer
1
不确定这是否值得一份负评。问题说,“有没有选项可以在类实例内获取属性名?”我展示了一个循环,它通过打印类实例中的所有属性名,但是他可以将要更新的属性名全部放入一个数组中,然后将其传递给Update过程。我不知道问题出在哪里。 - Vinay Sajip

2
您可以使用 PropertyInfo.Name 获取属性的名称(我假设您所说的 ID 是指名称)。只需循环遍历从 typeof(className).GetProperties() 返回的 PropertyInfo[] 即可。
foreach (PropertyInfo info in typeof(MyClass).GetProperties())
{
    string name = info.Name;
    // use name here
}

我希望我能给你+10分,这个太棒了 :) - Eric Herlitz

1
不确定这是否能为您提供所需,此代码将获取类中所有带有[Column]属性的属性: 在数据上下文中我有:
 public ReadOnlyCollection<MetaDataMember> ColumnNames<TEntity>( )
    {
        return this.Mapping.MappingSource.GetModel(typeof(DataContext)).GetMetaType(typeof(TEntity)).DataMembers;
    }

获取类中作为属性的表列名:
       MyDataContext db = GetDataContext(); 
       var allColumnPropertyNames =   db.ColumnNames<Animal>().Where(n => n.Member.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute), false).FirstOrDefault() != null).Select(n => n.Name);

1

假设(来自第一个示例,类MyClass的方法更新):

public class MyClass {

public int iMyStatusProperty { get; set; }
public int iMyKey { get; set; }

public int UpdateStatusProperty(int iValue){
this.iMyStatusProperty = iValue;
return _Update( new[iMyStatusProperty ], iMyKey); // this should generate SQL: "UPDATE MyClass set iMyStatusProperty = {iMyStatusProperty} where iMyKey = {iMyKey}"
}

{iMyStatusProperty}{iMyKey}是类实例的属性值。

因此,问题在于如何从属性中获取属性名称(反射),而不使用属性名称作为字符串(以避免字段名称拼写错误)。


1

既然您已经明确地拥有了指向您所需属性的句柄,您知道该属性的名称——那么您可以直接键入它吗?


我认为他希望代码也能适用于派生类,因此他需要使用反射。 - Zach Johnson
主要思想是不重复命名。因此,当编写一个带有属性的类时,我会得到自动生成表、CRUD语句和Intellisense - FrenkR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接