/Test/Mono.Cecil.Tests/CustomAttributesTests.cs

http://github.com/jbevain/cecil · C# · 679 lines · 505 code · 172 blank · 2 comment · 29 complexity · debd0687cb625139caff2cf5b7532326 MD5 · raw file

  1. using System;
  2. using System.Globalization;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Text;
  6. using Mono.Cecil;
  7. using Mono.Cecil.Metadata;
  8. using Mono.Cecil.PE;
  9. using NUnit.Framework;
  10. namespace Mono.Cecil.Tests {
  11. [TestFixture]
  12. public class CustomAttributesTests : BaseTestFixture {
  13. [Test]
  14. public void StringArgumentOnType ()
  15. {
  16. TestCSharp ("CustomAttributes.cs", module => {
  17. var hamster = module.GetType ("Hamster");
  18. Assert.IsTrue (hamster.HasCustomAttributes);
  19. Assert.AreEqual (1, hamster.CustomAttributes.Count);
  20. var attribute = hamster.CustomAttributes [0];
  21. Assert.AreEqual ("System.Void FooAttribute::.ctor(System.String)",
  22. attribute.Constructor.FullName);
  23. Assert.IsTrue (attribute.HasConstructorArguments);
  24. Assert.AreEqual (1, attribute.ConstructorArguments.Count);
  25. AssertArgument ("bar", attribute.ConstructorArguments [0]);
  26. });
  27. }
  28. [Test]
  29. public void NullString ()
  30. {
  31. TestCSharp ("CustomAttributes.cs", module => {
  32. var dentist = module.GetType ("Dentist");
  33. var attribute = GetAttribute (dentist, "Foo");
  34. Assert.IsNotNull (attribute);
  35. AssertArgument<string> (null, attribute.ConstructorArguments [0]);
  36. });
  37. }
  38. [Test]
  39. public void Primitives1 ()
  40. {
  41. TestCSharp ("CustomAttributes.cs", module => {
  42. var steven = module.GetType ("Steven");
  43. var attribute = GetAttribute (steven, "Foo");
  44. Assert.IsNotNull (attribute);
  45. AssertArgument<sbyte> (-12, attribute.ConstructorArguments [0]);
  46. AssertArgument<byte> (242, attribute.ConstructorArguments [1]);
  47. AssertArgument<bool> (true, attribute.ConstructorArguments [2]);
  48. AssertArgument<bool> (false, attribute.ConstructorArguments [3]);
  49. AssertArgument<ushort> (4242, attribute.ConstructorArguments [4]);
  50. AssertArgument<short> (-1983, attribute.ConstructorArguments [5]);
  51. AssertArgument<char> ('c', attribute.ConstructorArguments [6]);
  52. });
  53. }
  54. [Test]
  55. public void Primitives2 ()
  56. {
  57. TestCSharp ("CustomAttributes.cs", module => {
  58. var seagull = module.GetType ("Seagull");
  59. var attribute = GetAttribute (seagull, "Foo");
  60. Assert.IsNotNull (attribute);
  61. AssertArgument<int> (-100000, attribute.ConstructorArguments [0]);
  62. AssertArgument<uint> (200000, attribute.ConstructorArguments [1]);
  63. AssertArgument<float> (12.12f, attribute.ConstructorArguments [2]);
  64. AssertArgument<long> (long.MaxValue, attribute.ConstructorArguments [3]);
  65. AssertArgument<ulong> (ulong.MaxValue, attribute.ConstructorArguments [4]);
  66. AssertArgument<double> (64.646464, attribute.ConstructorArguments [5]);
  67. });
  68. }
  69. [Test]
  70. public void StringArgumentOnAssembly ()
  71. {
  72. TestCSharp ("CustomAttributes.cs", module => {
  73. var assembly = module.Assembly;
  74. var attribute = GetAttribute (assembly, "Foo");
  75. Assert.IsNotNull (attribute);
  76. AssertArgument ("bingo", attribute.ConstructorArguments [0]);
  77. });
  78. }
  79. [Test]
  80. public void CharArray ()
  81. {
  82. TestCSharp ("CustomAttributes.cs", module => {
  83. var rifle = module.GetType ("Rifle");
  84. var attribute = GetAttribute (rifle, "Foo");
  85. Assert.IsNotNull (attribute);
  86. var argument = attribute.ConstructorArguments [0];
  87. Assert.AreEqual ("System.Char[]", argument.Type.FullName);
  88. var array = argument.Value as CustomAttributeArgument [];
  89. Assert.IsNotNull (array);
  90. var str = "cecil";
  91. Assert.AreEqual (array.Length, str.Length);
  92. for (int i = 0; i < str.Length; i++)
  93. AssertArgument (str [i], array [i]);
  94. });
  95. }
  96. [Test]
  97. public void BoxedArguments ()
  98. {
  99. TestCSharp ("CustomAttributes.cs", module => {
  100. var worm = module.GetType ("Worm");
  101. var attribute = GetAttribute (worm, "Foo");
  102. Assert.IsNotNull (attribute);
  103. Assert.AreEqual (".ctor ((Object:(String:\"2\")), (Object:(I4:2)))", PrettyPrint (attribute));
  104. });
  105. }
  106. [Test]
  107. public void BoxedArraysArguments ()
  108. {
  109. TestCSharp ("CustomAttributes.cs", module => {
  110. var sheep = module.GetType ("Sheep");
  111. var attribute = GetAttribute (sheep, "Foo");
  112. Assert.IsNotNull (attribute);
  113. // [Foo (new object [] { "2", 2, 'c' }, new object [] { new object [] { 1, 2, 3}, null })]
  114. AssertCustomAttribute (".ctor ((Object:(Object[]:{(Object:(String:\"2\")), (Object:(I4:2)), (Object:(Char:'c'))})), (Object:(Object[]:{(Object:(Object[]:{(Object:(I4:1)), (Object:(I4:2)), (Object:(I4:3))})), (Object:(String:null))})))", attribute);
  115. });
  116. }
  117. [Test]
  118. public void FieldsAndProperties ()
  119. {
  120. TestCSharp ("CustomAttributes.cs", module => {
  121. var angola = module.GetType ("Angola");
  122. var attribute = GetAttribute (angola, "Foo");
  123. Assert.IsNotNull (attribute);
  124. Assert.AreEqual (2, attribute.Fields.Count);
  125. var argument = attribute.Fields.Where (a => a.Name == "Pan").First ();
  126. AssertCustomAttributeArgument ("(Object:(Object[]:{(Object:(I4:1)), (Object:(String:\"2\")), (Object:(Char:'3'))}))", argument);
  127. argument = attribute.Fields.Where (a => a.Name == "PanPan").First ();
  128. AssertCustomAttributeArgument ("(String[]:{(String:\"yo\"), (String:\"yo\")})", argument);
  129. Assert.AreEqual (2, attribute.Properties.Count);
  130. argument = attribute.Properties.Where (a => a.Name == "Bang").First ();
  131. AssertArgument (42, argument);
  132. argument = attribute.Properties.Where (a => a.Name == "Fiou").First ();
  133. AssertArgument<string> (null, argument);
  134. });
  135. }
  136. [Test]
  137. public void BoxedStringField ()
  138. {
  139. TestCSharp ("CustomAttributes.cs", module => {
  140. var type = module.GetType ("BoxedStringField");
  141. var attribute = GetAttribute (type, "Foo");
  142. Assert.IsNotNull (attribute);
  143. Assert.AreEqual (1, attribute.Fields.Count);
  144. var argument = attribute.Fields.Where (a => a.Name == "Pan").First ();
  145. AssertCustomAttributeArgument ("(Object:(String:\"fiouuu\"))", argument);
  146. });
  147. }
  148. [Test]
  149. public void TypeDefinitionEnum ()
  150. {
  151. TestCSharp ("CustomAttributes.cs", module => {
  152. var zero = module.GetType ("Zero");
  153. var attribute = GetAttribute (zero, "Foo");
  154. Assert.IsNotNull (attribute);
  155. Assert.AreEqual (1, attribute.ConstructorArguments.Count);
  156. Assert.AreEqual ((short) 2, attribute.ConstructorArguments [0].Value);
  157. Assert.AreEqual ("Bingo", attribute.ConstructorArguments [0].Type.FullName);
  158. });
  159. }
  160. [Test]
  161. public void TypeReferenceEnum ()
  162. {
  163. TestCSharp ("CustomAttributes.cs", module => {
  164. var ace = module.GetType ("Ace");
  165. var attribute = GetAttribute (ace, "Foo");
  166. Assert.IsNotNull (attribute);
  167. Assert.AreEqual (1, attribute.ConstructorArguments.Count);
  168. Assert.AreEqual ((byte) 0x04, attribute.ConstructorArguments [0].Value);
  169. Assert.AreEqual ("System.Security.AccessControl.AceFlags", attribute.ConstructorArguments [0].Type.FullName);
  170. Assert.AreEqual (module, attribute.ConstructorArguments [0].Type.Module);
  171. });
  172. }
  173. [Test]
  174. public void BoxedEnumReference ()
  175. {
  176. TestCSharp ("CustomAttributes.cs", module => {
  177. var bzzz = module.GetType ("Bzzz");
  178. var attribute = GetAttribute (bzzz, "Foo");
  179. Assert.IsNotNull (attribute);
  180. // [Foo (new object [] { Bingo.Fuel, Bingo.Binga }, null, Pan = System.Security.AccessControl.AceFlags.NoPropagateInherit)]
  181. Assert.AreEqual (2, attribute.ConstructorArguments.Count);
  182. var argument = attribute.ConstructorArguments [0];
  183. AssertCustomAttributeArgument ("(Object:(Object[]:{(Object:(Bingo:2)), (Object:(Bingo:4))}))", argument);
  184. argument = attribute.ConstructorArguments [1];
  185. AssertCustomAttributeArgument ("(Object:(String:null))", argument);
  186. argument = attribute.Fields.Where (a => a.Name == "Pan").First ().Argument;
  187. AssertCustomAttributeArgument ("(Object:(System.Security.AccessControl.AceFlags:4))", argument);
  188. });
  189. }
  190. [Test]
  191. public void TypeOfTypeDefinition ()
  192. {
  193. TestCSharp ("CustomAttributes.cs", module => {
  194. var typed = module.GetType ("Typed");
  195. var attribute = GetAttribute (typed, "Foo");
  196. Assert.IsNotNull (attribute);
  197. Assert.AreEqual (1, attribute.ConstructorArguments.Count);
  198. var argument = attribute.ConstructorArguments [0];
  199. Assert.AreEqual ("System.Type", argument.Type.FullName);
  200. var type = argument.Value as TypeDefinition;
  201. Assert.IsNotNull (type);
  202. Assert.AreEqual ("Bingo", type.FullName);
  203. });
  204. }
  205. [Test]
  206. public void TypeOfNestedTypeDefinition ()
  207. {
  208. TestCSharp ("CustomAttributes.cs", module => {
  209. var typed = module.GetType ("NestedTyped");
  210. var attribute = GetAttribute (typed, "Foo");
  211. Assert.IsNotNull (attribute);
  212. Assert.AreEqual (1, attribute.ConstructorArguments.Count);
  213. var argument = attribute.ConstructorArguments [0];
  214. Assert.AreEqual ("System.Type", argument.Type.FullName);
  215. var type = argument.Value as TypeDefinition;
  216. Assert.IsNotNull (type);
  217. Assert.AreEqual ("FooAttribute/Token", type.FullName);
  218. });
  219. }
  220. [Test]
  221. public void FieldTypeOf ()
  222. {
  223. TestCSharp ("CustomAttributes.cs", module => {
  224. var truc = module.GetType ("Truc");
  225. var attribute = GetAttribute (truc, "Foo");
  226. Assert.IsNotNull (attribute);
  227. var argument = attribute.Fields.Where (a => a.Name == "Chose").First ().Argument;
  228. Assert.AreEqual ("System.Type", argument.Type.FullName);
  229. var type = argument.Value as TypeDefinition;
  230. Assert.IsNotNull (type);
  231. Assert.AreEqual ("Typed", type.FullName);
  232. });
  233. }
  234. [Test]
  235. public void EscapedTypeName ()
  236. {
  237. TestModule ("bug-185.dll", module => {
  238. var foo = module.GetType ("Foo");
  239. var foo_do = foo.Methods.Where (m => !m.IsConstructor).First ();
  240. var attribute = foo_do.CustomAttributes.Where (ca => ca.AttributeType.Name == "AsyncStateMachineAttribute").First ();
  241. Assert.AreEqual (foo.NestedTypes [0], attribute.ConstructorArguments [0].Value);
  242. var function = module.GetType ("Function`1");
  243. var apply = function.Methods.Where(m => !m.IsConstructor).First ();
  244. attribute = apply.CustomAttributes.Where (ca => ca.AttributeType.Name == "AsyncStateMachineAttribute").First ();
  245. Assert.AreEqual (function.NestedTypes [0], attribute.ConstructorArguments [0].Value);
  246. });
  247. }
  248. [Test]
  249. public void FieldNullTypeOf ()
  250. {
  251. TestCSharp ("CustomAttributes.cs", module => {
  252. var truc = module.GetType ("Machin");
  253. var attribute = GetAttribute (truc, "Foo");
  254. Assert.IsNotNull (attribute);
  255. var argument = attribute.Fields.Where (a => a.Name == "Chose").First ().Argument;
  256. Assert.AreEqual ("System.Type", argument.Type.FullName);
  257. Assert.IsNull (argument.Value);
  258. });
  259. }
  260. [Test]
  261. public void OpenGenericTypeOf ()
  262. {
  263. TestCSharp ("CustomAttributes.cs", module => {
  264. var open_generic = module.GetType ("OpenGeneric`2");
  265. Assert.IsNotNull (open_generic);
  266. var attribute = GetAttribute (open_generic, "Foo");
  267. Assert.IsNotNull (attribute);
  268. Assert.AreEqual (1, attribute.ConstructorArguments.Count);
  269. var argument = attribute.ConstructorArguments [0];
  270. Assert.AreEqual ("System.Type", argument.Type.FullName);
  271. var type = argument.Value as TypeReference;
  272. Assert.IsNotNull (type);
  273. Assert.AreEqual ("System.Collections.Generic.Dictionary`2", type.FullName);
  274. });
  275. }
  276. [Test]
  277. public void ClosedGenericTypeOf ()
  278. {
  279. TestCSharp ("CustomAttributes.cs", module => {
  280. var closed_generic = module.GetType ("ClosedGeneric");
  281. Assert.IsNotNull (closed_generic);
  282. var attribute = GetAttribute (closed_generic, "Foo");
  283. Assert.IsNotNull (attribute);
  284. Assert.AreEqual (1, attribute.ConstructorArguments.Count);
  285. var argument = attribute.ConstructorArguments [0];
  286. Assert.AreEqual ("System.Type", argument.Type.FullName);
  287. var type = argument.Value as TypeReference;
  288. Assert.IsNotNull (type);
  289. Assert.AreEqual ("System.Collections.Generic.Dictionary`2<System.String,OpenGeneric`2<Machin,System.Int32>[,]>", type.FullName);
  290. });
  291. }
  292. [Test]
  293. public void TypeOfArrayOfNestedClass ()
  294. {
  295. TestCSharp ("CustomAttributes.cs", module => {
  296. var parent = module.GetType ("Parent");
  297. Assert.IsNotNull (parent);
  298. var attribute = GetAttribute (parent, "Foo");
  299. Assert.IsNotNull (attribute);
  300. Assert.AreEqual (1, attribute.ConstructorArguments.Count);
  301. var argument = attribute.ConstructorArguments [0];
  302. Assert.AreEqual ("System.Type", argument.Type.FullName);
  303. var type = argument.Value as TypeReference;
  304. Assert.IsNotNull (type);
  305. Assert.AreEqual ("Parent/Child[]", type.FullName);
  306. });
  307. }
  308. [Test]
  309. public void EmptyBlob ()
  310. {
  311. TestIL ("ca-empty-blob.il", module => {
  312. var attribute = module.GetType ("CustomAttribute");
  313. Assert.AreEqual (1, attribute.CustomAttributes.Count);
  314. Assert.AreEqual (0, attribute.CustomAttributes [0].ConstructorArguments.Count);
  315. }, verify: !Platform.OnMono);
  316. }
  317. [Test]
  318. public void InterfaceImplementation ()
  319. {
  320. OnlyOnWindows (); // Mono's ilasm doesn't support .interfaceimpl
  321. TestIL ("ca-iface-impl.il", module => {
  322. var type = module.GetType ("FooType");
  323. var iface = type.Interfaces.Single (i => i.InterfaceType.FullName == "IFoo");
  324. Assert.IsTrue (iface.HasCustomAttributes);
  325. var attributes = iface.CustomAttributes;
  326. Assert.AreEqual (1, attributes.Count);
  327. Assert.AreEqual ("FooAttribute", attributes [0].AttributeType.FullName);
  328. });
  329. }
  330. [Test]
  331. public void GenericParameterConstraint ()
  332. {
  333. TestModule ("GenericParameterConstraintAttributes.dll", module => {
  334. var type = module.GetType ("Foo.Library`1");
  335. var gp = type.GenericParameters.Single ();
  336. var constraint = gp.Constraints.Single ();
  337. Assert.IsTrue (constraint.HasCustomAttributes);
  338. var attributes = constraint.CustomAttributes;
  339. Assert.AreEqual (1, attributes.Count);
  340. Assert.AreEqual ("System.Runtime.CompilerServices.NullableAttribute", attributes [0].AttributeType.FullName);
  341. }, verify: !Platform.OnMono);
  342. }
  343. [Test]
  344. public void NullCharInString ()
  345. {
  346. TestCSharp ("CustomAttributes.cs", module => {
  347. var type = module.GetType ("NullCharInString");
  348. var attributes = type.CustomAttributes;
  349. Assert.AreEqual (1, attributes.Count);
  350. var attribute = attributes [0];
  351. Assert.AreEqual (1, attribute.ConstructorArguments.Count);
  352. var value = (string) attribute.ConstructorArguments [0].Value;
  353. Assert.AreEqual (8, value.Length);
  354. Assert.AreEqual ('\0', value [7]);
  355. });
  356. }
  357. [Test]
  358. public void OrderedAttributes ()
  359. {
  360. TestModule ("ordered-attrs.exe", module => {
  361. var type = module.GetType ("Program");
  362. var method = type.GetMethod ("Main");
  363. var attributes = method.CustomAttributes;
  364. Assert.AreEqual (6, attributes.Count);
  365. Assert.AreEqual ("AAttribute", attributes [0].AttributeType.Name);
  366. Assert.AreEqual ("Main.A1", attributes [0].Fields [0].Argument.Value as string);
  367. Assert.AreEqual ("AAttribute", attributes [1].AttributeType.Name);
  368. Assert.AreEqual ("Main.A2", attributes [1].Fields [0].Argument.Value as string);
  369. Assert.AreEqual ("BAttribute", attributes [2].AttributeType.Name);
  370. Assert.AreEqual ("Main.B1", attributes [2].Fields [0].Argument.Value as string);
  371. Assert.AreEqual ("AAttribute", attributes [3].AttributeType.Name);
  372. Assert.AreEqual ("Main.A3", attributes [3].Fields [0].Argument.Value as string);
  373. Assert.AreEqual ("BAttribute", attributes [4].AttributeType.Name);
  374. Assert.AreEqual ("Main.B2", attributes [4].Fields [0].Argument.Value as string);
  375. Assert.AreEqual ("BAttribute", attributes [5].AttributeType.Name);
  376. Assert.AreEqual ("Main.B3", attributes [5].Fields [0].Argument.Value as string);
  377. });
  378. }
  379. [Test]
  380. public void DefineCustomAttributeFromBlob ()
  381. {
  382. var file = Path.Combine (Path.GetTempPath (), "CaBlob.dll");
  383. var module = ModuleDefinition.CreateModule ("CaBlob.dll", new ModuleParameters { Kind = ModuleKind.Dll, Runtime = TargetRuntime.Net_2_0 });
  384. var assembly_title_ctor = module.ImportReference (typeof (System.Reflection.AssemblyTitleAttribute).GetConstructor (new [] {typeof (string)}));
  385. Assert.IsNotNull (assembly_title_ctor);
  386. var buffer = new ByteBuffer ();
  387. buffer.WriteUInt16 (1); // ca signature
  388. var title = Encoding.UTF8.GetBytes ("CaBlob");
  389. buffer.WriteCompressedUInt32 ((uint) title.Length);
  390. buffer.WriteBytes (title);
  391. buffer.WriteUInt16 (0); // named arguments
  392. var blob = new byte [buffer.length];
  393. Buffer.BlockCopy (buffer.buffer, 0, blob, 0, buffer.length);
  394. var attribute = new CustomAttribute (assembly_title_ctor, blob);
  395. module.Assembly.CustomAttributes.Add (attribute);
  396. module.Write (file);
  397. module = ModuleDefinition.ReadModule (file);
  398. attribute = GetAttribute (module.Assembly, "AssemblyTitle");
  399. Assert.IsNotNull (attribute);
  400. Assert.AreEqual ("CaBlob", (string) attribute.ConstructorArguments [0].Value);
  401. module.Dispose ();
  402. }
  403. static void AssertCustomAttribute (string expected, CustomAttribute attribute)
  404. {
  405. Assert.AreEqual (expected, PrettyPrint (attribute));
  406. }
  407. static void AssertCustomAttributeArgument (string expected, CustomAttributeNamedArgument named_argument)
  408. {
  409. AssertCustomAttributeArgument (expected, named_argument.Argument);
  410. }
  411. static void AssertCustomAttributeArgument (string expected, CustomAttributeArgument argument)
  412. {
  413. var result = new StringBuilder ();
  414. PrettyPrint (argument, result);
  415. Assert.AreEqual (expected, result.ToString ());
  416. }
  417. static string PrettyPrint (CustomAttribute attribute)
  418. {
  419. var signature = new StringBuilder ();
  420. signature.Append (".ctor (");
  421. for (int i = 0; i < attribute.ConstructorArguments.Count; i++) {
  422. if (i > 0)
  423. signature.Append (", ");
  424. PrettyPrint (attribute.ConstructorArguments [i], signature);
  425. }
  426. signature.Append (")");
  427. return signature.ToString ();
  428. }
  429. static void PrettyPrint (CustomAttributeArgument argument, StringBuilder signature)
  430. {
  431. var value = argument.Value;
  432. signature.Append ("(");
  433. PrettyPrint (argument.Type, signature);
  434. signature.Append (":");
  435. PrettyPrintValue (argument.Value, signature);
  436. signature.Append (")");
  437. }
  438. static void PrettyPrintValue (object value, StringBuilder signature)
  439. {
  440. if (value == null) {
  441. signature.Append ("null");
  442. return;
  443. }
  444. var arguments = value as CustomAttributeArgument [];
  445. if (arguments != null) {
  446. signature.Append ("{");
  447. for (int i = 0; i < arguments.Length; i++) {
  448. if (i > 0)
  449. signature.Append (", ");
  450. PrettyPrint (arguments [i], signature);
  451. }
  452. signature.Append ("}");
  453. return;
  454. }
  455. switch (Type.GetTypeCode (value.GetType ())) {
  456. case System.TypeCode.String:
  457. signature.AppendFormat ("\"{0}\"", value);
  458. break;
  459. case System.TypeCode.Char:
  460. signature.AppendFormat ("'{0}'", (char) value);
  461. break;
  462. default:
  463. var formattable = value as IFormattable;
  464. if (formattable != null) {
  465. signature.Append (formattable.ToString (null, CultureInfo.InvariantCulture));
  466. return;
  467. }
  468. if (value is CustomAttributeArgument) {
  469. PrettyPrint ((CustomAttributeArgument) value, signature);
  470. return;
  471. }
  472. break;
  473. }
  474. }
  475. static void PrettyPrint (TypeReference type, StringBuilder signature)
  476. {
  477. if (type.IsArray) {
  478. ArrayType array = (ArrayType) type;
  479. signature.AppendFormat ("{0}[]", array.ElementType.etype.ToString ());
  480. } else if (type.etype == ElementType.None) {
  481. signature.Append (type.FullName);
  482. } else
  483. signature.Append (type.etype.ToString ());
  484. }
  485. static void AssertArgument<T> (T value, CustomAttributeNamedArgument named_argument)
  486. {
  487. AssertArgument (value, named_argument.Argument);
  488. }
  489. static void AssertArgument<T> (T value, CustomAttributeArgument argument)
  490. {
  491. AssertArgument (typeof (T).FullName, (object) value, argument);
  492. }
  493. static void AssertArgument (string type, object value, CustomAttributeArgument argument)
  494. {
  495. Assert.AreEqual (type, argument.Type.FullName);
  496. Assert.AreEqual (value, argument.Value);
  497. }
  498. static CustomAttribute GetAttribute (ICustomAttributeProvider owner, string type)
  499. {
  500. Assert.IsTrue (owner.HasCustomAttributes);
  501. foreach (var attribute in owner.CustomAttributes)
  502. if (attribute.Constructor.DeclaringType.Name.StartsWith (type))
  503. return attribute;
  504. return null;
  505. }
  506. }
  507. }