AttributeHelper
在撰寫類別時,會希望在成員中可以多指定一些額外的資訊,以便在需要的時候取用。
這時候Attribute是個很好用的東西。屬性 (Attribute) 簡介
但因為大部分的類別成員都可以定義屬性(如欄位、Property、方法、建構子等…)
每次取屬性時都要用反射寫一些重複的Code,久而久之實在有點厭煩。
因此最近寫了一套通用取得屬性的Helper,方便以後來使用。
Note:在取Property的Attribute時很簡單,但為了有強型別可以使用,所以在這個Helper中
多增加一個多載是傳入Lambda,藉此可以用強型別的方式指定屬性名稱
使用方法:
//通常都會針對同一個Attribute做操作,因此這邊設計成可以先設定一個Attribute
//再用Get來對不同對象來取得
//如果只需要取一次,也可直接寫成
//AttributeHelper.SetAttribute<DescriptionAttribute>().Get<TModel>(...);
var descriptionAttr=AttributeHelper.SetAttribute<DescriptionAttribute>();
//類別
descriptionAttr.Get<Test>();
//屬性
descriptionAttr.Get<Test>(p=>p.Name);
//欄位
descriptionAttr.Get<Test>(p=>p.file);
//建構子1
descriptionAttr.Get<Test>(p=>new Test());
//建構子2
descriptionAttr.Get<Test>(p=>new Test(""));
//方法1
descriptionAttr.Get<Test>("GetString");
//方法2
descriptionAttr.Get<Test>("GetString",typeof(string));
//事件
descriptionAttr.Get<Test>("MyDelegate");
//委派
descriptionAttr.Get<Test>("MyEvent");
//列舉1
descriptionAttr.Get<付款方式>(p=>付款方式.信用卡);
//列舉2
付款方式 e=付款方式.現金;
descriptionAttr.Get<付款方式>(e.ToString());
結果:
ExpressionHelper 解析Expression,取回名稱及參數的Type
public class ExpressionHelper
{
/// <summary> 解析Expression,取回Member名稱及Parameter Type </summary>
public static ExpressionMemberInfo GetMemberName(Expression exp)
{
switch (exp.NodeType)
{
case ExpressionType.Convert:
case ExpressionType.TypeAs:
return GetMemberName(((UnaryExpression)exp).Operand);
case ExpressionType.Constant:
return GetExpressionMemberInfo(((ConstantExpression)exp).Value.ToString());
case ExpressionType.MemberAccess:
return GetExpressionMemberInfo(((MemberExpression)exp).Member.Name);
case ExpressionType.Call:
return VisitMethod((MethodCallExpression)exp);
case ExpressionType.Lambda:
return GetMemberName(((LambdaExpression)exp).Body);
case ExpressionType.New:
return VisitNew((NewExpression)exp);
default:
throw new NotSupportedException(String.Format("未處理的Expression : '{0}'", exp.NodeType));
}
}
private static ExpressionMemberInfo GetExpressionMemberInfo(string memberName)
{
return new ExpressionMemberInfo() { MemberName = memberName };
}
/// <summary> 解析MethodCallExpression </summary>
protected static ExpressionMemberInfo VisitMethod(MethodCallExpression methodExp)
{
return new ExpressionMemberInfo() {
MemberName = methodExp.Method.Name,
ParameterTypes = methodExp.Arguments.Select(p => p.Type) };
}
/// <summary> 解析NewExpression </summary>
protected static ExpressionMemberInfo VisitNew(NewExpression newExp)
{
return new ExpressionMemberInfo() {
MemberName = ".ctor",
ParameterTypes = newExp.Arguments.Select(p => p.Type) };
}
/// <summary> 解析完成後,回傳的類別(包含Member名稱跟Type的陣列) </summary>
public class ExpressionMemberInfo
{
public string MemberName { get; set; }
public IEnumerable<Type> ParameterTypes { get; set; }
}
}
AttributeHelper
public class AttributeHelper
{
#region -- 屬性與建構子 --
protected AttributeHelper()
{
}
protected BindingFlags _BindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
/// <summary> 設定BindingFlags </summary>
public BindingFlags SettingBindingFlags { get { return _BindingFlags; } set { _BindingFlags = value; } }
/// <summary> 要擷取的Attribute </summary>
protected Type AttributeType { get; set; }
#endregion
#region -- 方法 --
/// <summary> 設定要擷取的Attribute </summary>
public static AttributeHelper<T> SetAttribute<T>()
{
var helper = new AttributeHelper<T>();
helper.AttributeType = typeof(T);
return helper;
}
protected object GetMemberAttributes(Type type)
{
return type.GetCustomAttributes(false).FirstOrDefault();
}
protected object GetMemberAttributes(Type type, ExpressionHelper.ExpressionMemberInfo expressionMemberInfo)
{
MemberInfo memberInfo = null;
if (expressionMemberInfo.ParameterTypes == null)
{
memberInfo = type.GetMember(expressionMemberInfo.MemberName, _BindingFlags).FirstOrDefault();
}
else
{
memberInfo = type.GetMember(expressionMemberInfo.MemberName, _BindingFlags)
.FirstOrDefault(p => ((MethodBase)p).GetParameters()
.Select(s => s.ParameterType)
.SequenceEqual(expressionMemberInfo.ParameterTypes)
);
}
return GetResult(memberInfo);
}
private object GetResult(MemberInfo memberInfo)
{
if (memberInfo == null) throw new ArgumentNullException();
var attr = memberInfo.GetCustomAttributes(AttributeType, false).FirstOrDefault();
if (memberInfo == null) return null;
return attr;
}
#endregion
#region -- 快速使用區(如果有常用的Attribute,可以擴充在這邊) --
public static DescriptionAttribute GetDescription<TModel>()
{
return AttributeHelper.SetAttribute<DescriptionAttribute>().Get<TModel>();
}
public static DescriptionAttribute GetDescription<TModel>(string memberName, params Type[] types)
{
return AttributeHelper.SetAttribute<DescriptionAttribute>().Get<TModel>(memberName, types);
}
public static DescriptionAttribute GetDescription<TModel>(Expression<Func<TModel, object>> func)
{
return AttributeHelper.SetAttribute<DescriptionAttribute>().Get<TModel>(func);
}
#endregion
}
public class AttributeHelper<T> : AttributeHelper
{
protected internal AttributeHelper()
{
}
/// <summary> 取得類別的Attribute </summary>
public T Get<TModel>()
{
return (T)GetMemberAttributes(typeof(TModel));
}
/// <summary>
/// 取得指定成員名稱的Attribute
/// </summary>
/// <typeparam name="TModel">目標型別</typeparam>
/// <param name="memberName">成員名稱</param>
/// <param name="types">如果是MethodBase,可傳入參數的Type</param>
public T Get<TModel>(string memberName, params Type[] types)
{
return (T)GetMemberAttributes(typeof(TModel), new ExpressionHelper.ExpressionMemberInfo() { MemberName = memberName, ParameterTypes=types.ToList() });
}
/// <summary>
/// 取得指定成員名稱的Attribute
/// </summary>
/// <typeparam name="TModel">目標型別</typeparam>
/// <param name="func">可用Lambda的方式指定成員名稱</param>
public T Get<TModel>(Expression<Func<TModel, object>> func)
{
var expressionMemberInfo = ExpressionHelper.GetMemberName(func);
return (T)GetMemberAttributes(typeof(TModel), expressionMemberInfo);
}
}
測試類別:
[Description("測試類別")]
public class Test
{
[Description("建構子1")]
public Test()
{
}
[Description("建構子2")]
public Test(string name)
{
}
[Description("姓名")]
public string Name { get; set; }
[Description("年齡")]
public string Age;
[Description("方法1")]
public void GetString()
{
}
[Description("方法2")]
public void GetString(string name)
{
}
[Description("欄位")]
public string file = "";
[Description("委派")]
public delegate void MyDelegate();
[Description("事件")]
public event MyDelegate MyEvent;
}
public enum 付款方式
{
[Description("CreditCard")]
信用卡,
[Description("Cash")]
現金
}
目前測試大部分的情況都可以正常運作。
附上範例Code,如果有問題的話可以一起研究研究