Titleというカスタムプロパティを持つ1つのプロパティを持つTestというクラスがあるとします。
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のプロパティに関しては機能しません。
属性値を取得するには、属性が適用されるタイプが必要です。拡張メソッドは文字列値(Titleの値)しか取得しないため、文字列の実際のインスタンスを取得できず、Titleプロパティが属する元の型を取得できません。これにより、拡張メソッドから属性値を取得できなくなります。