Attribute鲜为人知的两个特性记录
??? Attribute作為一種標記在我們的.net中隨處可見,比如DatContract,DatMember,Serializable等等,各種用途的標記。是的我們的代碼更加簡潔,對于Attribute用好了,可以很好的簡化我們的開發,比如PostSharp的AOP實現就是一種基于Attribute的標記編譯時注入。在隨筆中有關于IOC,AOP利用Attribute標記簡化開發的實例。
?? 在使用Attribute時候發現了些鮮為人知的特性:
1:利用GetCustomAttributes傳入的Attribute返回得到包括派生類。
2:GetCustomAttributes每次返回的對象都是經過發射出來的沒有緩存。
?? 1:GetCustomAttributes傳入的Attribute返回得到包括派生類:
?????? 這里將采用一個測試類來驗證:
View Code [AttributeUsage(AttributeTargets.Class)]???public?class?TestImplementsAttribute?:?Attribute?
??{?
??????public?string?Name?
??????{?get;?set;?}?
??}
?
private?static?void?TestMutilpeImplements()?
{?
????var?type?=?typeof(Program);?
????var?attrs?=?type.GetCustomAttributes(typeof(TestImplementsAttribute),?false);?
????Console.WriteLine(string.Format("TestImplementsAttribute:({0})",attrs.Length));?
????foreach?(var?item?in?attrs)?
????{?
????????Console.WriteLine("??"?+?item.GetType().FullName);?
????}?
????attrs?=?type.GetCustomAttributes(typeof(SerializableAttribute),?false);?
????Console.WriteLine(string.Format("SerializableAttribute:({0})",?attrs.Length));?
????foreach?(var?item?in?attrs)?
????{?
????????Console.WriteLine("??"?+?item.GetType().FullName);?
????}?
????attrs?=?type.GetCustomAttributes(typeof(Attribute),?false);?
????Console.WriteLine(string.Format("(base?type)Attribute:({0})",?attrs.Length));?
????foreach?(var?item?in?attrs)?
????{?
????????Console.WriteLine("??"?+?item.GetType().FullName);?
????}?
}
輸出為:?
這里我們可以很清晰的看見當傳入Attribute類型時候返回包含了SerializableAttribute和TestImplementsAttribute兩個。
2:GetCustomAttributes每次返回的對象都是經過發射出來的沒有緩存:
測試代碼可以看出來,不是同一個地址引用:
private?static?void?TestAttributeActiver()???????{?
??????????var?type?=?typeof(Program);?
??????????var?attr1?=?type.GetCustomAttributes(typeof(TestImplementsAttribute),?false)[0];?
??????????var?attr2?=?type.GetCustomAttributes(typeof(TestImplementsAttribute),?false)[0];?
??????????Console.WriteLine(Object.ReferenceEquals(attr1,?attr2));????????????
??????}?
輸出值為false。?
我們在看看
.下面是 reflector的反編譯結果(Attribute.GetCustomAttributes):
View Code internal?static?unsafe?object[]?GetCustomAttributes(Module?decoratedModule,?int?decoratedMetadataToken,?int?pcaCount,?RuntimeType?attributeFilterType,?bool?mustBeInheritable,?IList?derivedAttributes){
????if?(decoratedModule.Assembly.ReflectionOnly)
????{
????????throw?new?InvalidOperationException(Environment.GetResourceString("Arg_ReflectionOnlyCA"));
????}
????MetadataImport?metadataImport?=?decoratedModule.MetadataImport;
????CustomAttributeRecord[]?customAttributeRecords?=?CustomAttributeData.GetCustomAttributeRecords(decoratedModule,?decoratedMetadataToken);
????Type?elementType?=?(((attributeFilterType?==?null)?||?attributeFilterType.IsValueType)?||?attributeFilterType.ContainsGenericParameters)???typeof(object)?:?attributeFilterType;
????if?((attributeFilterType?==?null)?&&?(customAttributeRecords.Length?==?0))
????{
????????return?(Array.CreateInstance(elementType,?0)?as?object[]);
????}
????object[]?attributes?=?Array.CreateInstance(elementType,?customAttributeRecords.Length)?as?object[];
????int?length?=?0;
????SecurityContextFrame?frame?=?new?SecurityContextFrame();
????frame.Push(decoratedModule.Assembly.InternalAssembly);
????Assembly?lastAptcaOkAssembly?=?null;
????for?(int?i?=?0;?i?<?customAttributeRecords.Length;?i++)
????{
????????bool?flag2;
????????bool?flag3;
????????object?obj2?=?null;
????????CustomAttributeRecord?caRecord?=?customAttributeRecords[i];
????????RuntimeMethodHandle?ctor?=?new?RuntimeMethodHandle();
????????RuntimeType?attributeType?=?null;
????????int?namedArgs?=?0;
????????IntPtr?signature?=?caRecord.blob.Signature;
????????IntPtr?blobEnd?=?(IntPtr)?(((void*)?signature)?+?caRecord.blob.Length);
????????if?(FilterCustomAttributeRecord(caRecord,?metadataImport,?ref?lastAptcaOkAssembly,?decoratedModule,?decoratedMetadataToken,?attributeFilterType,?mustBeInheritable,?attributes,?derivedAttributes,?out?attributeType,?out?ctor,?out?flag2,?out?flag3))
????????{
????????????if?(!ctor.IsNullHandle())
????????????{
????????????????ctor.CheckLinktimeDemands(decoratedModule,?decoratedMetadataToken);
????????????}
????????????RuntimeConstructorInfo.CheckCanCreateInstance(attributeType,?flag3);
????????????if?(flag2)
????????????{
????????????????obj2?=?CreateCaObject(decoratedModule,?ctor,?ref?signature,?blobEnd,?out?namedArgs);
????????????}
????????????else
????????????{
????????????????obj2?=?attributeType.TypeHandle.CreateCaInstance(ctor);
????????????????if?(Marshal.ReadInt16(signature)?!=?1)
????????????????{
????????????????????throw?new?CustomAttributeFormatException();
????????????????}
????????????????signature?=?(IntPtr)?(((void*)?signature)?+?2);
????????????????namedArgs?=?Marshal.ReadInt16(signature);
????????????????signature?=?(IntPtr)?(((void*)?signature)?+?2);
????????????}
????????????for?(int?j?=?0;?j?<?namedArgs;?j++)
????????????{
????????????????string?str;
????????????????bool?flag4;
????????????????Type?type3;
????????????????object?obj3;
????????????????IntPtr?ptr1?=?caRecord.blob.Signature;
????????????????GetPropertyOrFieldData(decoratedModule,?ref?signature,?blobEnd,?out?str,?out?flag4,?out?type3,?out?obj3);
????????????????try
????????????????{
????????????????????if?(flag4)
????????????????????{
????????????????????????if?((type3?==?null)?&&?(obj3?!=?null))
????????????????????????{
????????????????????????????type3?=?(obj3.GetType()?==?typeof(RuntimeType))???typeof(Type)?:?obj3.GetType();
????????????????????????}
????????????????????????RuntimePropertyInfo?property?=?null;
????????????????????????if?(type3?==?null)
????????????????????????{
????????????????????????????property?=?attributeType.GetProperty(str)?as?RuntimePropertyInfo;
????????????????????????}
????????????????????????else
????????????????????????{
????????????????????????????property?=?attributeType.GetProperty(str,?type3,?Type.EmptyTypes)?as?RuntimePropertyInfo;
????????????????????????}
????????????????????????RuntimeMethodInfo?setMethod?=?property.GetSetMethod(true)?as?RuntimeMethodInfo;
????????????????????????if?(setMethod.IsPublic)
????????????????????????{
????????????????????????????setMethod.MethodHandle.CheckLinktimeDemands(decoratedModule,?decoratedMetadataToken);
????????????????????????????setMethod.Invoke(obj2,?BindingFlags.Default,?null,?new?object[]?{?obj3?},?null,?true);
????????????????????????}
????????????????????}
????????????????????else
????????????????????{
????????????????????????(attributeType.GetField(str)?as?RtFieldInfo).InternalSetValue(obj2,?obj3,?BindingFlags.Default,?Type.DefaultBinder,?null,?false);
????????????????????}
????????????????}
????????????????catch?(Exception?exception)
????????????????{
????????????????????throw?new?CustomAttributeFormatException(string.Format(CultureInfo.CurrentUICulture,?Environment.GetResourceString(flag4???"RFLCT.InvalidPropFail"?:?"RFLCT.InvalidFieldFail"),?new?object[]?{?str?}),?exception);
????????????????}
????????????}
????????????if?(!signature.Equals(blobEnd))
????????????{
????????????????throw?new?CustomAttributeFormatException();
????????????}
????????????attributes[length++]?=?obj2;
????????}
????}
????frame.Pop();
????if?((length?==?customAttributeRecords.Length)?&&?(pcaCount?==?0))
????{
????????return?attributes;
????}
????if?(length?==?0)
????{
????????Array.CreateInstance(elementType,?0);
????}
????object[]?destinationArray?=?Array.CreateInstance(elementType,?(int)?(length?+?pcaCount))?as?object[];
????Array.Copy(attributes,?0,?destinationArray,?0,?length);
????return?destinationArray;
}
在這里我們可以見數組的創建CreateInstance等等。
?? 同時可以參見老趙前輩以前的關于Attribute反射的一次失敗的嘗試(上):原來GetCustomAttributes方法每次都返回新的實例和一次失敗的嘗試(下):無法使用泛型的Attribute。
?? 不知道為什么在Attribute參數的檢查是在我們的編譯時期,參數必須是常量表達式,卻在這里需要每次反射。
?? 本篇隨筆只是個人使用心得記錄,請勿拍磚。
總結
以上是生活随笔為你收集整理的Attribute鲜为人知的两个特性记录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 某个知名技术论坛用户名和密码泄露(第一部
- 下一篇: Silverlight Blend动画