C# 高階特性(二)Attribute和反射
使用Attribute的時候大多需要用到反射,所以放在一起。
Attribute:
我的理解是,它可以給你的類、方法、欄位等新增一些描述性語言,在執行期間又可以通過反射的方法獲取它的內容。
在編譯期間就初始化好了。
反射:
通過反射可以在不瞭解物件的內容時,操作物件。
優點:在執行的時候才需要獲取物件內容,提示程式的靈活性,降低耦合等。
缺點:操作效率低,會暴露私有的屬性和方法等。
舉例:
我有一個父類Animal,他有四個子類:Cat、Dog、Lion、Tiger。
public class Animal
{ }
public class Cat : Animal
{ }
public class Dog : Animal
{ }
public class Lion : Animal
{ }
public class Tiger : Animal
{ }
假設我們需要寫一個方法,描述動物叫聲的大小,我們認為Cat和Dog的叫聲小,屬於一類,Lion和Tiger的叫聲大,屬於一類。
如果不用Attribute和反射機制,那麼我們需要給每個動物都定義叫聲這個方法。但是,如果用Attribute和反射機制用的話,則,我們可以把Cat和Dog定義一個方法,Lion和Tiger定義一個方法。
定義一個自定義attribute:
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class CallBindingAttribute : Attribute
{
private Type m_CallType;
public Type CallType
{
get { return m_CallType; }
}
internal CallBindingAttribute(Type callType)
{
m_CallType = callType;
}
}
定義動物叫聲:
public class CallType
{
public enum Level
{
LOW = 1,
HIGH = 2
}
private Level m_CallLevel;
public Level CallLevel
{
get { return m_CallLevel; }
internal set { m_CallLevel = value; }
}
}
定義大型動物和小動物叫聲,並繫結我們自定義的屬性:
[CallBinding(typeof(Cat))]
[CallBinding(typeof(Dog))]
public class SmallAnimalType : CallType
{
public SmallAnimalType()
{
this.CallLevel = Level.LOW;
}
}
[CallBinding(typeof(Lion))]
[CallBinding(typeof(Tiger))]
public class BigAnimalType : CallType
{
public BigAnimalType()
{
this.CallLevel = Level.HIGH;
}
}
通過反射獲取合適動物叫聲:
public static List<CallType> Calls = new List<CallType>();
public static List<CallType> GetFaultTypes(Type type)
{
List<CallType> cts = new List<CallType>();
foreach (CallType ct in Calls)
{
object[] os = ct.GetType().GetCustomAttributes(typeof(CallBindingAttribute), false); // 反射方法,通過繫結的CallBindingAttribute和類獲取到合適的叫聲
foreach (CallBindingAttribute dba in os)
{
if (dba.CallType == type || type.IsSubclassOf(dba.CallType))
{
cts.Add(ct);
break;
}
}
}
return cts;
}
根據動物型別獲取到動物叫聲:
SmallAnimalType sType = new SmallAnimalType(); // 載入動物叫聲
Calls.Add(sType);
BigAnimalType bType = new BigAnimalType();
Calls.Add(bType);
Dog dog = new Dog();
List<CallType> DogCall = GetFaultTypes(dog.GetType()); // 根據動物型別Dog獲取狗的叫聲
foreach (CallType callType in DogCall)
{
Console.WriteLine(callType.CallLevel.ToString()); //輸出為獅子的叫聲 HIGH
}
List<CallType> LionCall = GetFaultTypes(lion.GetType());
foreach (CallType callType in LionCall)
{
Console.WriteLine(callType.CallLevel.ToString());//輸出為狗的叫聲 LOW
}