Initial commit
[mono.git] / mcs / class / referencesource / mscorlib / system / attribute.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6
7 namespace System {
8
9     using System;
10     using System.Reflection;
11     using System.Collections.Generic;
12     using System.Runtime.InteropServices;
13     using System.Globalization;
14     using System.Diagnostics.Contracts;
15     using System.Security;
16     using System.Security.Permissions;
17
18     [Serializable]
19     [AttributeUsageAttribute(AttributeTargets.All, Inherited = true, AllowMultiple=false)] 
20     [ClassInterface(ClassInterfaceType.None)]
21     [ComDefaultInterface(typeof(_Attribute))]
22     [System.Runtime.InteropServices.ComVisible(true)]
23     public abstract class Attribute : _Attribute
24     {
25         #region Private Statics
26
27         #region PropertyInfo
28         private static Attribute[] InternalGetCustomAttributes(PropertyInfo element, Type type, bool inherit)
29         {
30             Contract.Requires(element != null);
31             Contract.Requires(type != null);
32             Contract.Requires(type.IsSubclassOf(typeof(Attribute)) || type == typeof(Attribute));
33
34             // walk up the hierarchy chain
35             Attribute[] attributes = (Attribute[])element.GetCustomAttributes(type, inherit);
36
37             if (!inherit)
38                 return attributes;
39
40             // create the hashtable that keeps track of inherited types
41             Dictionary<Type, AttributeUsageAttribute> types = new Dictionary<Type, AttributeUsageAttribute>(11);
42
43             // create an array list to collect all the requested attibutes
44             List<Attribute> attributeList = new List<Attribute>();
45             CopyToArrayList(attributeList, attributes, types);
46
47             PropertyInfo baseProp = GetParentDefinition(element);
48             while (baseProp != null)
49             {
50                 attributes = GetCustomAttributes(baseProp, type, false);
51                 AddAttributesToList(attributeList, attributes, types);
52                 baseProp = GetParentDefinition(baseProp);
53             }
54             Array array = CreateAttributeArrayHelper(type, attributeList.Count);
55             Array.Copy(attributeList.ToArray(), 0, array, 0, attributeList.Count);
56             return (Attribute[])array;
57         }
58
59         private static bool InternalIsDefined(PropertyInfo element, Type attributeType, bool inherit)
60         {
61             // walk up the hierarchy chain
62             if (element.IsDefined(attributeType, inherit))
63                 return true;
64             
65             if (inherit)
66             {
67                 AttributeUsageAttribute usage = InternalGetAttributeUsage(attributeType);
68
69                 if (!usage.Inherited) 
70                     return false;
71
72                 PropertyInfo baseProp = GetParentDefinition(element);
73
74                 while (baseProp != null)
75                 {
76                     if (baseProp.IsDefined(attributeType, false))
77                         return true;
78
79                     baseProp = GetParentDefinition(baseProp);
80                 }
81             }
82
83             return false;
84         }
85
86         private static PropertyInfo GetParentDefinition(PropertyInfo property)
87         {
88             Contract.Requires(property != null);
89
90             // for the current property get the base class of the getter and the setter, they might be different
91             // note that this only works for RuntimeMethodInfo
92             MethodInfo propAccessor = property.GetGetMethod(true); 
93
94             if (propAccessor == null) 
95                 propAccessor = property.GetSetMethod(true);
96
97             RuntimeMethodInfo rtPropAccessor = propAccessor as RuntimeMethodInfo;
98
99             if (rtPropAccessor != null)
100             {
101                 rtPropAccessor = rtPropAccessor.GetParentDefinition();
102
103                 if (rtPropAccessor != null)
104                                 {
105 #if FEATURE_LEGACYNETCF
106                     // Mimicing NetCF which only looks for public properties.
107                     if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
108                         return rtPropAccessor.DeclaringType.GetProperty(property.Name, property.PropertyType);
109 #endif //FEATURE_LEGACYNETCF
110
111                     // There is a public overload of Type.GetProperty that takes both a BingingFlags enum and a return type.
112                     // However, we cannot use that because it doesn't accept null for "types".
113                     return rtPropAccessor.DeclaringType.GetProperty(
114                         property.Name,
115                         BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly,
116                         property.PropertyType);
117                                 }
118             }
119
120             return null;
121         }
122
123         #endregion
124
125         #region EventInfo
126         private static Attribute[] InternalGetCustomAttributes(EventInfo element, Type type, bool inherit)
127         {
128             Contract.Requires(element != null);
129             Contract.Requires(type != null);
130             Contract.Requires(type.IsSubclassOf(typeof(Attribute)) || type == typeof(Attribute));
131
132             // walk up the hierarchy chain
133             Attribute[] attributes = (Attribute[])element.GetCustomAttributes(type, inherit);
134             if (inherit)
135             {
136                 // create the hashtable that keeps track of inherited types
137                 Dictionary<Type, AttributeUsageAttribute> types = new Dictionary<Type, AttributeUsageAttribute>(11);
138                 // create an array list to collect all the requested attibutes
139                 List<Attribute> attributeList = new List<Attribute>();
140                 CopyToArrayList(attributeList, attributes, types);
141
142                 EventInfo baseEvent = GetParentDefinition(element);
143                 while (baseEvent != null)
144                 {
145                     attributes = GetCustomAttributes(baseEvent, type, false);
146                     AddAttributesToList(attributeList, attributes, types);
147                     baseEvent = GetParentDefinition(baseEvent);
148                 }
149                 Array array = CreateAttributeArrayHelper(type, attributeList.Count);
150                 Array.Copy(attributeList.ToArray(), 0, array, 0, attributeList.Count);
151                 return (Attribute[])array;
152             }
153             else
154                 return attributes;
155         }
156
157         private static EventInfo GetParentDefinition(EventInfo ev)
158         {
159             Contract.Requires(ev != null);
160
161             // note that this only works for RuntimeMethodInfo
162             MethodInfo add = ev.GetAddMethod(true);
163
164             RuntimeMethodInfo rtAdd = add as RuntimeMethodInfo;
165
166             if (rtAdd != null)
167             {
168                 rtAdd = rtAdd.GetParentDefinition();
169                 if (rtAdd != null) 
170                     return rtAdd.DeclaringType.GetEvent(ev.Name);
171             }
172             return null;
173         }
174
175         private static bool InternalIsDefined (EventInfo element, Type attributeType, bool inherit)
176         {
177             Contract.Requires(element != null);
178
179             // walk up the hierarchy chain
180             if (element.IsDefined(attributeType, inherit))
181                 return true;
182             
183             if (inherit)
184             {
185                 AttributeUsageAttribute usage = InternalGetAttributeUsage(attributeType);
186
187                 if (!usage.Inherited) 
188                     return false;
189
190                 EventInfo baseEvent = GetParentDefinition(element);
191
192                 while (baseEvent != null)
193                 {
194                     if (baseEvent.IsDefined(attributeType, false))
195                         return true;
196                     baseEvent = GetParentDefinition(baseEvent);
197                 }
198             }
199
200             return false;
201         }
202
203         #endregion
204
205         #region ParameterInfo
206         private static ParameterInfo GetParentDefinition(ParameterInfo param)
207         {
208             Contract.Requires(param != null);
209
210             // note that this only works for RuntimeMethodInfo
211             RuntimeMethodInfo rtMethod = param.Member as RuntimeMethodInfo;
212
213             if (rtMethod != null)
214             {
215                 rtMethod = rtMethod.GetParentDefinition();
216
217                 if (rtMethod != null)
218                 {
219                     // Find the ParameterInfo on this method
220                     ParameterInfo[] parameters = rtMethod.GetParameters();
221                     return parameters[param.Position]; // Point to the correct ParameterInfo of the method
222                 }
223             }
224             return null;
225         }
226
227         private static Attribute[] InternalParamGetCustomAttributes(ParameterInfo param, Type type, bool inherit)
228         {
229             Contract.Requires(param != null);
230
231             // For ParameterInfo's we need to make sure that we chain through all the MethodInfo's in the inheritance chain that
232             // have this ParameterInfo defined. .We pick up all the CustomAttributes for the starting ParameterInfo. We need to pick up only attributes 
233             // that are marked inherited from the remainder of the MethodInfo's in the inheritance chain.
234             // For MethodInfo's on an interface we do not do an inheritance walk so the default ParameterInfo attributes are returned.
235             // For MethodInfo's on a class we walk up the inheritance chain but do not look at the MethodInfo's on the interfaces that the
236             // class inherits from and return the respective ParameterInfo attributes
237
238             List<Type> disAllowMultiple = new List<Type>();
239             Object [] objAttr;
240
241             if (type == null)
242                 type = typeof(Attribute);
243
244             objAttr = param.GetCustomAttributes(type, false); 
245                 
246             for (int i =0;i < objAttr.Length;i++)
247             {
248                 Type objType = objAttr[i].GetType();
249                 AttributeUsageAttribute attribUsage = InternalGetAttributeUsage(objType);
250                 if (attribUsage.AllowMultiple == false)
251                     disAllowMultiple.Add(objType);
252             }
253
254             // Get all the attributes that have Attribute as the base class
255             Attribute [] ret = null;
256             if (objAttr.Length == 0) 
257                 ret = CreateAttributeArrayHelper(type,0);
258             else 
259                 ret = (Attribute[])objAttr;
260             
261             if (param.Member.DeclaringType == null) // This is an interface so we are done.
262                 return ret;
263             
264             if (!inherit) 
265                 return ret;
266
267             ParameterInfo baseParam = GetParentDefinition(param);
268
269             while (baseParam != null)
270             {
271                 objAttr = baseParam.GetCustomAttributes(type, false); 
272                 
273                 int count = 0;
274                 for (int i =0;i < objAttr.Length;i++)
275                 {
276                     Type objType = objAttr[i].GetType();
277                     AttributeUsageAttribute attribUsage = InternalGetAttributeUsage(objType);
278
279                     if ((attribUsage.Inherited) && (disAllowMultiple.Contains(objType) == false))
280                     {
281                         if (attribUsage.AllowMultiple == false)
282                             disAllowMultiple.Add(objType);
283                         count++;
284                     }
285                     else
286                         objAttr[i] = null;
287                 }
288
289                 // Get all the attributes that have Attribute as the base class
290                 Attribute [] attributes = CreateAttributeArrayHelper(type,count);
291                 
292                 count = 0;
293                 for (int i =0;i < objAttr.Length;i++)
294                 {
295                     if (objAttr[i] != null)
296                     {
297                         attributes[count] = (Attribute)objAttr[i];
298                         count++;
299                     }
300                 }
301                 
302                 Attribute [] temp = ret;
303                 ret = CreateAttributeArrayHelper(type,temp.Length + count);
304                 Array.Copy(temp,ret,temp.Length);
305                 
306                 int offset = temp.Length;
307
308                 for (int i =0;i < attributes.Length;i++) 
309                     ret[offset + i] = attributes[i];
310
311                 baseParam = GetParentDefinition(baseParam);
312             } 
313
314             return ret;
315         }
316
317         private static bool InternalParamIsDefined(ParameterInfo param, Type type, bool inherit)
318         {
319             Contract.Requires(param != null);
320             Contract.Requires(type != null);
321
322             // For ParameterInfo's we need to make sure that we chain through all the MethodInfo's in the inheritance chain.
323             // We pick up all the CustomAttributes for the starting ParameterInfo. We need to pick up only attributes 
324             // that are marked inherited from the remainder of the ParameterInfo's in the inheritance chain.
325             // For MethodInfo's on an interface we do not do an inheritance walk. For ParameterInfo's on a
326             // Class we walk up the inheritance chain but do not look at the MethodInfo's on the interfaces that the class inherits from.
327
328             if (param.IsDefined(type, false))
329                 return true;
330             
331             if (param.Member.DeclaringType == null || !inherit) // This is an interface so we are done.
332                 return false;
333
334             ParameterInfo baseParam = GetParentDefinition(param);
335
336             while (baseParam != null)
337             {
338                 Object[] objAttr = baseParam.GetCustomAttributes(type, false); 
339                                 
340                 for (int i =0; i < objAttr.Length; i++)
341                 {
342                     Type objType = objAttr[i].GetType();
343                     AttributeUsageAttribute attribUsage = InternalGetAttributeUsage(objType);
344
345                     if ((objAttr[i] is Attribute) && (attribUsage.Inherited))
346                         return true;
347                 }
348
349                 baseParam = GetParentDefinition(baseParam);
350             } 
351
352             return false;
353         }
354
355         #endregion
356
357         #region Utility
358         private static void CopyToArrayList(List<Attribute> attributeList,Attribute[] attributes,Dictionary<Type, AttributeUsageAttribute> types) 
359         {
360             for (int i = 0; i < attributes.Length; i++) 
361             {
362                 attributeList.Add(attributes[i]);
363
364                 Type attrType = attributes[i].GetType();
365
366                 if (!types.ContainsKey(attrType)) 
367                     types[attrType] = InternalGetAttributeUsage(attrType);
368             }
369         }
370
371         private static void AddAttributesToList(List<Attribute> attributeList, Attribute[] attributes, Dictionary<Type, AttributeUsageAttribute> types) 
372         {
373             for (int i = 0; i < attributes.Length; i++) 
374             {
375                 Type attrType = attributes[i].GetType();
376                 AttributeUsageAttribute usage = null;
377                 types.TryGetValue(attrType, out usage);
378
379                 if (usage == null) 
380                 {
381                     // the type has never been seen before if it's inheritable add it to the list
382                     usage = InternalGetAttributeUsage(attrType);
383                     types[attrType] = usage;
384
385                     if (usage.Inherited) 
386                         attributeList.Add(attributes[i]);
387                 }
388                 else if (usage.Inherited && usage.AllowMultiple)
389                 {
390                     // we saw this type already add it only if it is inheritable and it does allow multiple 
391                     attributeList.Add(attributes[i]);
392                 }
393             }
394         }
395
396         private static AttributeUsageAttribute InternalGetAttributeUsage(Type type)
397         {
398             // Check if the custom attributes is Inheritable
399             Object [] obj = type.GetCustomAttributes(typeof(AttributeUsageAttribute), false); 
400
401             if (obj.Length == 1)
402                 return (AttributeUsageAttribute)obj[0];
403
404             if (obj.Length == 0)
405                 return AttributeUsageAttribute.Default;
406
407             throw new FormatException(
408                 Environment.GetResourceString("Format_AttributeUsage", type));
409         }
410
411         [System.Security.SecuritySafeCritical]
412         private static Attribute[] CreateAttributeArrayHelper(Type elementType, int elementCount)
413         {
414             return (Attribute[])Array.UnsafeCreateInstance(elementType, elementCount);
415         }
416         #endregion
417
418         #endregion
419
420         #region Public Statics
421
422         #region MemberInfo
423         public static Attribute[] GetCustomAttributes(MemberInfo element, Type type)
424         {
425             return GetCustomAttributes(element, type, true);
426         }
427         
428         public static Attribute[] GetCustomAttributes(MemberInfo element, Type type, bool inherit)
429         {
430             if (element == null)
431                 throw new ArgumentNullException("element");
432
433             if (type == null)
434                 throw new ArgumentNullException("type");
435             
436             if (!type.IsSubclassOf(typeof(Attribute)) && type != typeof(Attribute))
437                 throw new ArgumentException(Environment.GetResourceString("Argument_MustHaveAttributeBaseClass"));
438             Contract.EndContractBlock();
439
440             switch (element.MemberType)
441             {
442                 case MemberTypes.Property:  
443                     return InternalGetCustomAttributes((PropertyInfo)element, type, inherit);
444
445                 case MemberTypes.Event: 
446                     return InternalGetCustomAttributes((EventInfo)element, type, inherit);
447
448                 default:
449                     return element.GetCustomAttributes(type, inherit) as Attribute[];
450             }
451         }
452
453         public static Attribute[] GetCustomAttributes(MemberInfo element)
454         {
455             return GetCustomAttributes(element, true);
456         }
457
458         public static Attribute[] GetCustomAttributes(MemberInfo element, bool inherit)
459         {
460             if (element == null)
461                 throw new ArgumentNullException("element");
462             Contract.EndContractBlock();
463
464             switch (element.MemberType)
465             {
466                 case MemberTypes.Property:  
467                     return InternalGetCustomAttributes((PropertyInfo)element, typeof(Attribute), inherit);
468
469                 case MemberTypes.Event: 
470                     return InternalGetCustomAttributes((EventInfo)element, typeof(Attribute), inherit);
471
472                 default:
473                     return element.GetCustomAttributes(typeof(Attribute), inherit) as Attribute[];
474             }
475         }
476         
477         public static bool IsDefined(MemberInfo element, Type attributeType)
478         {
479             return IsDefined(element, attributeType, true);
480         }
481
482         public static bool IsDefined(MemberInfo element, Type attributeType, bool inherit)
483         {
484             // Returns true if a custom attribute subclass of attributeType class/interface with inheritance walk
485             if (element == null)
486                 throw new ArgumentNullException("element");
487
488             if (attributeType == null)
489                 throw new ArgumentNullException("attributeType");
490             
491             if (!attributeType.IsSubclassOf(typeof(Attribute)) && attributeType != typeof(Attribute))
492                 throw new ArgumentException(Environment.GetResourceString("Argument_MustHaveAttributeBaseClass"));
493             Contract.EndContractBlock();
494
495             switch(element.MemberType)
496             {
497                 case MemberTypes.Property:  
498                     return InternalIsDefined((PropertyInfo)element, attributeType, inherit);
499
500                 case MemberTypes.Event: 
501                     return InternalIsDefined((EventInfo)element, attributeType, inherit);
502
503                 default:
504                     return element.IsDefined(attributeType, inherit);
505             }
506
507         }
508
509         public static Attribute GetCustomAttribute(MemberInfo element, Type attributeType)
510         {
511             return GetCustomAttribute(element, attributeType, true);
512         }
513
514         public static Attribute GetCustomAttribute(MemberInfo element, Type attributeType, bool inherit)
515         {
516             Attribute[] attrib = GetCustomAttributes(element, attributeType, inherit);
517
518             if (attrib == null || attrib.Length == 0)
519                 return null;
520
521             if (attrib.Length == 1)
522                 return attrib[0];
523
524             throw new AmbiguousMatchException(Environment.GetResourceString("RFLCT.AmbigCust"));
525         }
526
527         #endregion
528
529         #region ParameterInfo
530         public static Attribute[] GetCustomAttributes(ParameterInfo element)
531         {
532             return GetCustomAttributes(element, true);
533         }
534         
535         public static Attribute[] GetCustomAttributes(ParameterInfo element, Type attributeType)
536         {
537             return (Attribute[])GetCustomAttributes(element, attributeType, true);
538         }
539
540         public static Attribute[] GetCustomAttributes(ParameterInfo element, Type attributeType, bool inherit)
541         {
542             if (element == null)
543                 throw new ArgumentNullException("element");
544
545             if (attributeType == null)
546                 throw new ArgumentNullException("attributeType");
547             
548             if (!attributeType.IsSubclassOf(typeof(Attribute)) && attributeType != typeof(Attribute))
549                 throw new ArgumentException(Environment.GetResourceString("Argument_MustHaveAttributeBaseClass"));
550
551             if (element.Member == null)
552                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidParameterInfo"), "element");
553
554             Contract.EndContractBlock();
555
556             MemberInfo member = element.Member;
557             if (member.MemberType == MemberTypes.Method && inherit) 
558                 return InternalParamGetCustomAttributes(element, attributeType, inherit) as Attribute[];
559
560             return element.GetCustomAttributes(attributeType, inherit) as Attribute[];
561         }
562
563         public static Attribute[] GetCustomAttributes(ParameterInfo element, bool inherit)
564         {
565             if (element == null)
566                 throw new ArgumentNullException("element");
567
568             if (element.Member == null)
569                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidParameterInfo"), "element");
570
571             Contract.EndContractBlock();
572
573             MemberInfo member = element.Member;
574             if (member.MemberType == MemberTypes.Method && inherit) 
575                 return InternalParamGetCustomAttributes(element, null, inherit) as Attribute[];
576             
577             return element.GetCustomAttributes(typeof(Attribute), inherit) as Attribute[];
578         }
579
580         public static bool IsDefined(ParameterInfo element, Type attributeType)
581         {
582             return IsDefined(element, attributeType, true);
583         }
584
585         public static bool IsDefined(ParameterInfo element, Type attributeType, bool inherit)
586         {
587             // Returns true is a custom attribute subclass of attributeType class/interface with inheritance walk
588             if (element == null)
589                 throw new ArgumentNullException("element");
590
591             if (attributeType == null)
592                 throw new ArgumentNullException("attributeType");
593             
594             if (!attributeType.IsSubclassOf(typeof(Attribute)) && attributeType != typeof(Attribute))
595                 throw new ArgumentException(Environment.GetResourceString("Argument_MustHaveAttributeBaseClass"));
596             Contract.EndContractBlock();
597
598             MemberInfo member = element.Member;
599
600             switch(member.MemberType)
601             {
602                 case MemberTypes.Method: // We need to climb up the member hierarchy            
603                     return InternalParamIsDefined(element, attributeType, inherit);
604
605                 case MemberTypes.Constructor:
606                     return element.IsDefined(attributeType, false);
607
608                 case MemberTypes.Property:
609                     return element.IsDefined(attributeType, false);
610
611                 default: 
612                     Contract.Assert(false, "Invalid type for ParameterInfo member in Attribute class");
613                     throw new ArgumentException(Environment.GetResourceString("Argument_InvalidParamInfo"));
614             }
615         }
616
617         public static Attribute GetCustomAttribute(ParameterInfo element, Type attributeType)
618         {
619             return GetCustomAttribute(element, attributeType, true);
620         }
621
622         public static Attribute GetCustomAttribute(ParameterInfo element, Type attributeType, bool inherit)
623         {
624             // Returns an Attribute of base class/inteface attributeType on the ParameterInfo or null if none exists.
625             // throws an AmbiguousMatchException if there are more than one defined.
626             Attribute[] attrib = GetCustomAttributes(element, attributeType, inherit);
627
628             if (attrib == null || attrib.Length == 0)
629                 return null;
630
631             if (attrib.Length == 0)
632                 return null;
633
634             if (attrib.Length == 1)
635                 return attrib[0];
636
637             throw new AmbiguousMatchException(Environment.GetResourceString("RFLCT.AmbigCust"));
638         }
639
640         #endregion
641
642         #region Module
643         public static Attribute[] GetCustomAttributes(Module element, Type attributeType)
644         {
645             return GetCustomAttributes (element, attributeType, true);
646         }
647
648         public static Attribute[] GetCustomAttributes(Module element)
649         {
650             return GetCustomAttributes(element, true);
651         }
652
653         public static Attribute[] GetCustomAttributes(Module element, bool inherit)
654         {
655             if (element == null)
656                 throw new ArgumentNullException("element");
657             Contract.EndContractBlock();
658
659             return (Attribute[])element.GetCustomAttributes(typeof(Attribute), inherit);
660         }
661
662         public static Attribute[] GetCustomAttributes(Module element, Type attributeType, bool inherit)
663         {
664             if (element == null)
665                 throw new ArgumentNullException("element");
666
667             if (attributeType == null)
668                 throw new ArgumentNullException("attributeType");
669
670             if (!attributeType.IsSubclassOf(typeof(Attribute)) && attributeType != typeof(Attribute))
671                 throw new ArgumentException(Environment.GetResourceString("Argument_MustHaveAttributeBaseClass"));
672             Contract.EndContractBlock();
673
674             return (Attribute[])element.GetCustomAttributes(attributeType, inherit);
675         }
676
677         public static bool IsDefined(Module element, Type attributeType)
678         {
679             return IsDefined(element, attributeType, false);
680         }
681
682         public static bool IsDefined(Module element, Type attributeType, bool inherit)
683         {
684             // Returns true is a custom attribute subclass of attributeType class/interface with no inheritance walk
685             if (element == null)
686                 throw new ArgumentNullException("element");
687
688             if (attributeType == null)
689                 throw new ArgumentNullException("attributeType");
690
691             if (!attributeType.IsSubclassOf(typeof(Attribute)) && attributeType != typeof(Attribute))
692                 throw new ArgumentException(Environment.GetResourceString("Argument_MustHaveAttributeBaseClass"));
693             Contract.EndContractBlock();
694
695             return element.IsDefined(attributeType,false);
696         }
697
698         public static Attribute GetCustomAttribute(Module element, Type attributeType)
699         {
700             return GetCustomAttribute(element, attributeType, true);
701         }
702
703         public static Attribute GetCustomAttribute(Module element, Type attributeType, bool inherit)
704         {
705             // Returns an Attribute of base class/inteface attributeType on the Module or null if none exists.
706             // throws an AmbiguousMatchException if there are more than one defined.
707             Attribute[] attrib = GetCustomAttributes(element,attributeType,inherit);
708
709             if (attrib == null || attrib.Length == 0)
710                 return null;
711
712             if (attrib.Length == 1)
713                 return attrib[0];
714
715             throw new AmbiguousMatchException(Environment.GetResourceString("RFLCT.AmbigCust"));
716         }
717
718         #endregion
719
720         #region Assembly
721         public static Attribute[] GetCustomAttributes(Assembly element, Type attributeType)
722         {
723             return GetCustomAttributes(element, attributeType, true);
724         }
725
726         public static Attribute[] GetCustomAttributes(Assembly element, Type attributeType, bool inherit)
727         {
728             if (element == null)
729                 throw new ArgumentNullException("element");
730
731             if (attributeType == null)
732                 throw new ArgumentNullException("attributeType");
733
734             if (!attributeType.IsSubclassOf(typeof(Attribute)) && attributeType != typeof(Attribute))
735                 throw new ArgumentException(Environment.GetResourceString("Argument_MustHaveAttributeBaseClass"));
736             Contract.EndContractBlock();
737
738             return (Attribute[])element.GetCustomAttributes(attributeType, inherit);
739         }
740
741         public static Attribute[] GetCustomAttributes(Assembly element)
742         {
743             return GetCustomAttributes(element, true);
744         }
745
746         public static Attribute[] GetCustomAttributes(Assembly element, bool inherit)
747         {
748             if (element == null)
749                 throw new ArgumentNullException("element");
750             Contract.EndContractBlock();
751
752             return (Attribute[])element.GetCustomAttributes(typeof(Attribute), inherit);
753         }
754
755         public static bool IsDefined (Assembly element, Type attributeType)
756         {
757             return IsDefined (element, attributeType, true);
758         }
759
760         public static bool IsDefined (Assembly element, Type attributeType, bool inherit)
761         {
762             // Returns true is a custom attribute subclass of attributeType class/interface with no inheritance walk
763             if (element == null)
764                 throw new ArgumentNullException("element");
765
766             if (attributeType == null)
767                 throw new ArgumentNullException("attributeType");
768
769             if (!attributeType.IsSubclassOf(typeof(Attribute)) && attributeType != typeof(Attribute))
770                 throw new ArgumentException(Environment.GetResourceString("Argument_MustHaveAttributeBaseClass"));
771             Contract.EndContractBlock();
772
773             return element.IsDefined(attributeType, false);
774         }
775
776         public static Attribute GetCustomAttribute(Assembly element, Type attributeType)
777         {
778             return GetCustomAttribute (element, attributeType, true);
779         }
780
781         public static Attribute GetCustomAttribute(Assembly element, Type attributeType, bool inherit)
782         {
783             // Returns an Attribute of base class/inteface attributeType on the Assembly or null if none exists.
784             // throws an AmbiguousMatchException if there are more than one defined.
785             Attribute[] attrib = GetCustomAttributes(element,attributeType,inherit);
786
787             if (attrib == null || attrib.Length == 0)
788                 return null;
789
790             if (attrib.Length == 1)
791                 return attrib[0];
792
793             throw new AmbiguousMatchException(Environment.GetResourceString("RFLCT.AmbigCust"));
794         }
795
796         #endregion
797
798         #endregion
799
800         #region Constructor
801         protected Attribute() { }
802         #endregion
803
804         #region Object Overrides
805         [SecuritySafeCritical]
806         public override bool Equals(Object obj)
807         {
808             if (obj == null)
809                 return false;
810
811             RuntimeType thisType = (RuntimeType)this.GetType();
812             RuntimeType thatType = (RuntimeType)obj.GetType();
813
814             if (thatType != thisType)
815                 return false;
816
817             Object thisObj = this;
818             Object thisResult, thatResult;
819
820             FieldInfo[] thisFields = thisType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
821
822             for (int i = 0; i < thisFields.Length; i++)
823             {
824                 // Visibility check and consistency check are not necessary.
825                 thisResult = ((RtFieldInfo)thisFields[i]).UnsafeGetValue(thisObj);
826                 thatResult = ((RtFieldInfo)thisFields[i]).UnsafeGetValue(obj);
827
828                 if (!AreFieldValuesEqual(thisResult, thatResult))
829                 {
830                     return false;
831                 }
832             }
833
834             return true;
835         }
836
837         // Compares values of custom-attribute fields.    
838         private static bool AreFieldValuesEqual(Object thisValue, Object thatValue)
839         {
840             if (thisValue == null && thatValue == null)
841                 return true;
842             if (thisValue == null || thatValue == null)
843                 return false;
844
845             if (thisValue.GetType().IsArray)
846             {
847                 // Ensure both are arrays of the same type.
848                 if (!thisValue.GetType().Equals(thatValue.GetType()))
849                 {
850                     return false;
851                 }
852
853                 Array thisValueArray = thisValue as Array;
854                 Array thatValueArray = thatValue as Array;
855                 if (thisValueArray.Length != thatValueArray.Length)
856                 {
857                     return false;
858                 }
859
860                 // Attributes can only contain single-dimension arrays, so we don't need to worry about 
861                 // multidimensional arrays.
862                 Contract.Assert(thisValueArray.Rank == 1 && thatValueArray.Rank == 1);
863                 for (int j = 0; j < thisValueArray.Length; j++)
864                 {
865                     if (!AreFieldValuesEqual(thisValueArray.GetValue(j), thatValueArray.GetValue(j)))
866                     {
867                         return false;
868                     }
869                 }
870             }
871             else
872             {
873                 // An object of type Attribute will cause a stack overflow. 
874                 // However, this should never happen because custom attributes cannot contain values other than
875                 // constants, single-dimensional arrays and typeof expressions.
876                 Contract.Assert(!(thisValue is Attribute));
877                 if (!thisValue.Equals(thatValue))
878                     return false;
879             }
880
881             return true;
882         }
883
884         [SecuritySafeCritical]
885         public override int GetHashCode()
886         {
887             Type type = GetType();
888
889             FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
890             Object vThis = null;
891
892             for (int i = 0; i < fields.Length; i++)
893             {
894                 // Visibility check and consistency check are not necessary.
895                 Object fieldValue = ((RtFieldInfo)fields[i]).UnsafeGetValue(this);
896
897                 // The hashcode of an array ignores the contents of the array, so it can produce 
898                 // different hashcodes for arrays with the same contents.
899                 // Since we do deep comparisons of arrays in Equals(), this means Equals and GetHashCode will
900                 // be inconsistent for arrays. Therefore, we ignore hashes of arrays.
901                 if (fieldValue != null && !fieldValue.GetType().IsArray)
902                     vThis = fieldValue;
903
904                 if (vThis != null)
905                     break;
906             }
907
908             if (vThis != null)
909                 return vThis.GetHashCode();
910
911             return type.GetHashCode();
912         }
913         #endregion
914
915         #region Public Virtual Members
916         public virtual Object TypeId { get { return GetType(); } }
917         
918         public virtual bool Match(Object obj) { return Equals(obj); }
919         #endregion
920
921         #region Public Members
922         public virtual bool IsDefaultAttribute() { return false; }
923         #endregion
924
925         void _Attribute.GetTypeInfoCount(out uint pcTInfo)
926         {
927             throw new NotImplementedException();
928         }
929
930         void _Attribute.GetTypeInfo(uint iTInfo, uint lcid, IntPtr ppTInfo)
931         {
932             throw new NotImplementedException();
933         }
934
935         void _Attribute.GetIDsOfNames([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
936         {
937             throw new NotImplementedException();
938         }
939
940         void _Attribute.Invoke(uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
941         {
942             throw new NotImplementedException();
943         }
944     }
945 }