假设我有一个名为 Test 的类,其中有一个名为 Title 的属性,并且具有自定义属性:
public class Test
{
[DatabaseField("title")]
public string Title { get; set; }
}
还有一个名为 DbField 的扩展方法。我想知道在 c# 中是否可以从对象实例获取自定义属性。
Test t = new Test();
string fieldName = t.Title.DbField();
//fieldName will equal "title", the same name passed into the attribute above
这可以吗?
这是一种方法。扩展方法有效,但并不那么容易。我创建一个表达式,然后检索自定义属性。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace ConsoleApplication1
{
public class DatabaseFieldAttribute : Attribute
{
public string Name { get; set; }
public DatabaseFieldAttribute(string name)
{
this.Name = name;
}
}
public static class MyClassExtensions
{
public static string DbField<T>(this T obj, Expression<Func<T, string>> value)
{
var memberExpression = value.Body as MemberExpression;
var attr = memberExpression.Member.GetCustomAttributes(typeof(DatabaseFieldAttribute), true);
return ((DatabaseFieldAttribute)attr[0]).Name;
}
}
class Program
{
static void Main(string[] args)
{
var p = new Program();
Console.WriteLine("DbField = '{0}'", p.DbField(v => v.Title));
}
[DatabaseField("title")]
public string Title { get; set; }
}
}
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
Test t = new Test();
Console.WriteLine(t.FieldName("Title").FieldName<DatabaseFieldAttribute>());
Console.WriteLine(t.FieldName("Title").FieldIsPrimaryKey<DatabaseFieldAttribute>());
}
}
public class Test
{
[DatabaseField("titlezzz", true)]
public string Title
{
get;
set;
}
}
public class BaseDatabaseFieldAttribute : Attribute
{
private readonly string _name;
public string Name { get { return _name; } }
public BaseDatabaseFieldAttribute(string name)
{
_name = name;
}
}
public class DatabaseFieldAttribute : BaseDatabaseFieldAttribute
{
private readonly bool _isPrimaryKey;
public bool IsPrimaryKey { get { return _isPrimaryKey; } }
public DatabaseFieldAttribute(string name, bool isPrimaryKey): base(name)
{
_isPrimaryKey = isPrimaryKey;
}
}
public static class Helper
{
public static PropertyInfo FieldName(this object obj, string propertyName)
{
return obj.GetType().GetProperty(propertyName);
}
public static string FieldName<T>(this PropertyInfo property) where T: BaseDatabaseFieldAttribute
{
object[] os = property.GetCustomAttributes(typeof(T), false);
if (os != null && os.Length >= 1)
return (os[0] as T).Name;
else
return "N/A";
}
public static bool? FieldIsPrimaryKey<T>(this PropertyInfo property) where T : DatabaseFieldAttribute
{
object[] os = property.GetCustomAttributes(typeof(T), false);
if (os != null && os.Length >= 1)
return (os[0] as T).IsPrimaryKey;
else
return null;
}
}
}
确实如此,但最终这将是一种迂回的方式,因为您将通过在公开属性的实例上调用
Type
来获取 GetType
实例,然后对其进行处理(通常情况下)。
在这种特定情况下,您的扩展方法将无法获取属性信息,因为您传递给它的只是一个字符串。
最终,您需要的是从中获得房产的
PropertyInfo
。其他答案都指的是Type
,他们缺少的是,这不是在你想要的PropertyInfo
处获取属性信息的唯一方法。
您可以通过传递带有字符串(大概是属性名称)的
Type
实例来实现此目的,这样您就可以在 GetProperty
上调用 Type
。
自 C# 3.0 以来执行此操作的另一种方法是使用一种方法,该方法采用
Expression<T>
,然后使用 Expression
的部分来获取 PropertyInfo
。在这种情况下,您将采用 Expression<Func<string>>
或 TResult
为字符串的内容。
一旦获得
PropertyInfo
,您就可以在其上调用 GetCustomAttributes
,并查找您的属性。
表达式方法的优点是
Expression<T>
派生自LambdaExpression
,您可以调用Compile
,然后根据需要调用以获取实际值。
正如所指出的,使用原始发帖人描述的语法是不可能的,因为您无法在扩展方法中获取对 PropertyInfo 的引用。像这样的事情怎么样:
// Extension method
public static string GetDbField(this object obj, string propertyName)
{
PropertyInfo prop = obj.GetType().GetProperty(propertyName);
object[] dbFieldAtts = prop.GetCustomAttributes(typeof(DatabaseFieldAttribute), true);
if (dbFieldAtts != null && dbFieldAtts.Length > 0)
{
return ((DatabaseFieldAttribute)dbFieldAtts[0]).Name;
}
return "UNDEFINED";
}
您可以简单地获取信息:
Test t = new Test();
string dbField = t.GetDbField("Title");
不,这是不可能的。原因是它是值,而不是属性本身将被发送到任何获取此信息的自定义扩展方法中。一旦进入该扩展方法,就没有可靠的方法可以追溯到属性本身。
对于枚举值来说可能是可能的,但就 POCO 上的属性而言,这是行不通的。
特定属性的枚举。
public static IEnumerable<TAttribute> GetAttributes<TAttribute>(this Type type) where TAttribute : Attribute
{
if (type.GetCustomAttributes<TAttribute>(true).Any())
foreach (var atribute in type.GetCustomAttributes<TAttribute>(true))
yield return atribute;
}
public static IEnumerable<TAttribute> GetAttributes<TAttribute>(this Assembly assembly) where TAttribute : Attribute
{
return assembly.GetTypes().Where(type => type.GetCustomAttributes<TAttribute>(true).Any()).SelectMany(x => GetAttributes<TAttribute>(x)).AsEnumerable();
}
可以进一步增强这些以使用表达式/谓词返回所需的结果。
public static IEnumerable<TAttribute> GetAttributes<TAttribute>(this Type type, Func<TAttribute, bool> predicate) where TAttribute : Attribute
{
if (type.GetCustomAttributes<TAttribute>(true).Any())
{
var attributes = type.GetCustomAttributes<TAttribute>(true).Where(predicate);
foreach (var atribute in attributes) yield return atribute;
}
}
public static IEnumerable<TAttribute> GetAttributes<TAttribute>(this Assembly assembly, Func<TAttribute, bool> predicate) where TAttribute : Attribute => assembly.GetTypes()
.Where(type => type.GetCustomAttributes<TAttribute>(true).Any())
.SelectMany(x => GetAttributes<TAttribute>(x))
.Where(predicate)
.AsEnumerable();
以上这些方法是通用的,需要属性类型来获取类中的相关属性。例如
var modules = typeof(IEntity).Assembly.GetAttributes<Module>();
var modules = typeof(MyClass).GetAttributes<Module>();