PageRenderTime 45ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/mcs/class/System.Xaml/System.Xaml/XamlType.cs

https://bitbucket.org/danipen/mono
C# | 834 lines | 630 code | 129 blank | 75 comment | 218 complexity | 748b2e1859d9886e13a968ef0a113f25 MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. //
  2. // Copyright (C) 2010 Novell Inc. http://novell.com
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining
  5. // a copy of this software and associated documentation files (the
  6. // "Software"), to deal in the Software without restriction, including
  7. // without limitation the rights to use, copy, modify, merge, publish,
  8. // distribute, sublicense, and/or sell copies of the Software, and to
  9. // permit persons to whom the Software is furnished to do so, subject to
  10. // the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be
  13. // included in all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  19. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  20. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  21. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. //
  23. using System;
  24. using System.Collections;
  25. using System.Collections.Generic;
  26. using System.ComponentModel;
  27. using System.Linq;
  28. using System.Reflection;
  29. using System.Windows.Markup;
  30. using System.Xaml.Schema;
  31. using System.Xml.Serialization;
  32. namespace System.Xaml
  33. {
  34. public class XamlType : IEquatable<XamlType>
  35. {
  36. public XamlType (Type underlyingType, XamlSchemaContext schemaContext)
  37. : this (underlyingType, schemaContext, null)
  38. {
  39. }
  40. // static readonly Type [] predefined_types = {
  41. // typeof (XData), typeof (Uri), typeof (TimeSpan), typeof (PropertyDefinition), typeof (MemberDefinition), typeof (Reference)
  42. // };
  43. public XamlType (Type underlyingType, XamlSchemaContext schemaContext, XamlTypeInvoker invoker)
  44. : this (schemaContext, invoker)
  45. {
  46. if (underlyingType == null)
  47. throw new ArgumentNullException ("underlyingType");
  48. type = underlyingType;
  49. underlying_type = type;
  50. XamlType xt;
  51. if (XamlLanguage.InitializingTypes) {
  52. // These are special. Only XamlLanguage members are with shorthand name.
  53. if (type == typeof (PropertyDefinition))
  54. Name = "Property";
  55. else if (type == typeof (MemberDefinition))
  56. Name = "Member";
  57. else
  58. Name = GetXamlName (type);
  59. PreferredXamlNamespace = XamlLanguage.Xaml2006Namespace;
  60. } else if ((xt = XamlLanguage.AllTypes.FirstOrDefault (t => t.UnderlyingType == type)) != null) {
  61. Name = xt.Name;
  62. PreferredXamlNamespace = XamlLanguage.Xaml2006Namespace;
  63. } else {
  64. Name = GetXamlName (type);
  65. PreferredXamlNamespace = schemaContext.GetXamlNamespace (type.Namespace) ?? String.Format ("clr-namespace:{0};assembly={1}", type.Namespace, type.Assembly.GetName ().Name);
  66. }
  67. if (type.IsGenericType) {
  68. TypeArguments = new List<XamlType> ();
  69. foreach (var gta in type.GetGenericArguments ())
  70. TypeArguments.Add (schemaContext.GetXamlType (gta));
  71. }
  72. }
  73. public XamlType (string unknownTypeNamespace, string unknownTypeName, IList<XamlType> typeArguments, XamlSchemaContext schemaContext)
  74. : this (schemaContext, null)
  75. {
  76. if (unknownTypeNamespace == null)
  77. throw new ArgumentNullException ("unknownTypeNamespace");
  78. if (unknownTypeName == null)
  79. throw new ArgumentNullException ("unknownTypeName");
  80. if (schemaContext == null)
  81. throw new ArgumentNullException ("schemaContext");
  82. type = typeof (object);
  83. Name = unknownTypeName;
  84. PreferredXamlNamespace = unknownTypeNamespace;
  85. TypeArguments = typeArguments != null && typeArguments.Count == 0 ? null : typeArguments;
  86. // explicit_ns = unknownTypeNamespace;
  87. }
  88. protected XamlType (string typeName, IList<XamlType> typeArguments, XamlSchemaContext schemaContext)
  89. : this (String.Empty, typeName, typeArguments, schemaContext)
  90. {
  91. }
  92. XamlType (XamlSchemaContext schemaContext, XamlTypeInvoker invoker)
  93. {
  94. if (schemaContext == null)
  95. throw new ArgumentNullException ("schemaContext");
  96. SchemaContext = schemaContext;
  97. this.invoker = invoker ?? new XamlTypeInvoker (this);
  98. }
  99. Type type, underlying_type;
  100. // string explicit_ns;
  101. // populated properties
  102. XamlType base_type;
  103. XamlTypeInvoker invoker;
  104. internal EventHandler<XamlSetMarkupExtensionEventArgs> SetMarkupExtensionHandler {
  105. get { return LookupSetMarkupExtensionHandler (); }
  106. }
  107. internal EventHandler<XamlSetTypeConverterEventArgs> SetTypeConverterHandler {
  108. get { return LookupSetTypeConverterHandler (); }
  109. }
  110. public IList<XamlType> AllowedContentTypes {
  111. get { return LookupAllowedContentTypes (); }
  112. }
  113. public XamlType BaseType {
  114. get { return LookupBaseType (); }
  115. }
  116. public bool ConstructionRequiresArguments {
  117. get { return LookupConstructionRequiresArguments (); }
  118. }
  119. public XamlMember ContentProperty {
  120. get { return LookupContentProperty (); }
  121. }
  122. public IList<XamlType> ContentWrappers {
  123. get { return LookupContentWrappers (); }
  124. }
  125. public XamlValueConverter<XamlDeferringLoader> DeferringLoader {
  126. get { return LookupDeferringLoader (); }
  127. }
  128. public XamlTypeInvoker Invoker {
  129. get { return LookupInvoker (); }
  130. }
  131. public bool IsAmbient {
  132. get { return LookupIsAmbient (); }
  133. }
  134. public bool IsArray {
  135. get { return LookupCollectionKind () == XamlCollectionKind.Array; }
  136. }
  137. // it somehow treats array as not a collection...
  138. public bool IsCollection {
  139. get { return LookupCollectionKind () == XamlCollectionKind.Collection; }
  140. }
  141. public bool IsConstructible {
  142. get { return LookupIsConstructible (); }
  143. }
  144. public bool IsDictionary {
  145. get { return LookupCollectionKind () == XamlCollectionKind.Dictionary; }
  146. }
  147. public bool IsGeneric {
  148. get { return type.IsGenericType; }
  149. }
  150. public bool IsMarkupExtension {
  151. get { return LookupIsMarkupExtension (); }
  152. }
  153. public bool IsNameScope {
  154. get { return LookupIsNameScope (); }
  155. }
  156. public bool IsNameValid {
  157. get { return XamlLanguage.IsValidXamlName (Name); }
  158. }
  159. public bool IsNullable {
  160. get { return LookupIsNullable (); }
  161. }
  162. public bool IsPublic {
  163. get { return LookupIsPublic (); }
  164. }
  165. public bool IsUnknown {
  166. get { return LookupIsUnknown (); }
  167. }
  168. public bool IsUsableDuringInitialization {
  169. get { return LookupUsableDuringInitialization (); }
  170. }
  171. public bool IsWhitespaceSignificantCollection {
  172. get { return LookupIsWhitespaceSignificantCollection (); }
  173. }
  174. public bool IsXData {
  175. get { return LookupIsXData (); }
  176. }
  177. public XamlType ItemType {
  178. get { return LookupItemType (); }
  179. }
  180. public XamlType KeyType {
  181. get { return LookupKeyType (); }
  182. }
  183. public XamlType MarkupExtensionReturnType {
  184. get { return LookupMarkupExtensionReturnType (); }
  185. }
  186. public string Name { get; private set; }
  187. public string PreferredXamlNamespace { get; private set; }
  188. public XamlSchemaContext SchemaContext { get; private set; }
  189. public bool TrimSurroundingWhitespace {
  190. get { return LookupTrimSurroundingWhitespace (); }
  191. }
  192. public IList<XamlType> TypeArguments { get; private set; }
  193. public XamlValueConverter<TypeConverter> TypeConverter {
  194. get { return LookupTypeConverter (); }
  195. }
  196. public Type UnderlyingType {
  197. get { return LookupUnderlyingType (); }
  198. }
  199. public XamlValueConverter<ValueSerializer> ValueSerializer {
  200. get { return LookupValueSerializer (); }
  201. }
  202. internal string GetInternalXmlName ()
  203. {
  204. if (IsMarkupExtension && Name.EndsWith ("Extension", StringComparison.Ordinal))
  205. return Name.Substring (0, Name.Length - 9);
  206. var stn = XamlLanguage.SpecialNames.FirstOrDefault (s => s.Type == this);
  207. return stn != null ? stn.Name : Name;
  208. }
  209. public static bool operator == (XamlType left, XamlType right)
  210. {
  211. return IsNull (left) ? IsNull (right) : left.Equals (right);
  212. }
  213. static bool IsNull (XamlType a)
  214. {
  215. return Object.ReferenceEquals (a, null);
  216. }
  217. public static bool operator != (XamlType left, XamlType right)
  218. {
  219. return !(left == right);
  220. }
  221. public bool Equals (XamlType other)
  222. {
  223. // It does not compare XamlSchemaContext.
  224. return !IsNull (other) &&
  225. UnderlyingType == other.UnderlyingType &&
  226. Name == other.Name &&
  227. PreferredXamlNamespace == other.PreferredXamlNamespace && TypeArguments.ListEquals (other.TypeArguments);
  228. }
  229. public override bool Equals (object obj)
  230. {
  231. var a = obj as XamlType;
  232. return Equals (a);
  233. }
  234. public override int GetHashCode ()
  235. {
  236. if (UnderlyingType != null)
  237. return UnderlyingType.GetHashCode ();
  238. int x = Name.GetHashCode () << 7 + PreferredXamlNamespace.GetHashCode ();
  239. if (TypeArguments != null)
  240. foreach (var t in TypeArguments)
  241. x = t.GetHashCode () + x << 5;
  242. return x;
  243. }
  244. public override string ToString ()
  245. {
  246. return new XamlTypeName (this).ToString ();
  247. //return String.IsNullOrEmpty (PreferredXamlNamespace) ? Name : String.Concat ("{", PreferredXamlNamespace, "}", Name);
  248. }
  249. public virtual bool CanAssignTo (XamlType xamlType)
  250. {
  251. if (this.UnderlyingType == null)
  252. return xamlType == XamlLanguage.Object;
  253. var ut = xamlType.UnderlyingType ?? typeof (object);
  254. return ut.IsAssignableFrom (UnderlyingType);
  255. }
  256. public XamlMember GetAliasedProperty (XamlDirective directive)
  257. {
  258. return LookupAliasedProperty (directive);
  259. }
  260. public ICollection<XamlMember> GetAllAttachableMembers ()
  261. {
  262. return new List<XamlMember> (LookupAllAttachableMembers ());
  263. }
  264. public ICollection<XamlMember> GetAllMembers ()
  265. {
  266. return new List<XamlMember> (LookupAllMembers ());
  267. }
  268. public XamlMember GetAttachableMember (string name)
  269. {
  270. return LookupAttachableMember (name);
  271. }
  272. public XamlMember GetMember (string name)
  273. {
  274. return LookupMember (name, true);
  275. }
  276. public IList<XamlType> GetPositionalParameters (int parameterCount)
  277. {
  278. return LookupPositionalParameters (parameterCount);
  279. }
  280. public virtual IList<string> GetXamlNamespaces ()
  281. {
  282. throw new NotImplementedException ();
  283. /* this does not work like documented!
  284. if (explicit_ns != null)
  285. return new string [] {explicit_ns};
  286. var l = SchemaContext.GetAllXamlNamespaces ();
  287. if (l != null)
  288. return new List<string> (l);
  289. return new string [] {String.Empty};
  290. */
  291. }
  292. // lookups
  293. protected virtual XamlMember LookupAliasedProperty (XamlDirective directive)
  294. {
  295. if (directive == XamlLanguage.Key) {
  296. var a = this.GetCustomAttribute<DictionaryKeyPropertyAttribute> ();
  297. return a != null ? GetMember (a.Name) : null;
  298. }
  299. if (directive == XamlLanguage.Name) {
  300. var a = this.GetCustomAttribute<RuntimeNamePropertyAttribute> ();
  301. return a != null ? GetMember (a.Name) : null;
  302. }
  303. if (directive == XamlLanguage.Uid) {
  304. var a = this.GetCustomAttribute<UidPropertyAttribute> ();
  305. return a != null ? GetMember (a.Name) : null;
  306. }
  307. if (directive == XamlLanguage.Lang) {
  308. var a = this.GetCustomAttribute<XmlLangPropertyAttribute> ();
  309. return a != null ? GetMember (a.Name) : null;
  310. }
  311. return null;
  312. }
  313. protected virtual IEnumerable<XamlMember> LookupAllAttachableMembers ()
  314. {
  315. if (UnderlyingType == null)
  316. return BaseType != null ? BaseType.GetAllAttachableMembers () : empty_array;
  317. if (all_attachable_members_cache == null) {
  318. all_attachable_members_cache = new List<XamlMember> (DoLookupAllAttachableMembers ());
  319. all_attachable_members_cache.Sort (TypeExtensionMethods.CompareMembers);
  320. }
  321. return all_attachable_members_cache;
  322. }
  323. IEnumerable<XamlMember> DoLookupAllAttachableMembers ()
  324. {
  325. // based on http://msdn.microsoft.com/en-us/library/ff184560.aspx
  326. var bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
  327. var gl = new Dictionary<string,MethodInfo> ();
  328. var sl = new Dictionary<string,MethodInfo> ();
  329. var al = new Dictionary<string,MethodInfo> ();
  330. //var rl = new Dictionary<string,MethodInfo> ();
  331. var nl = new List<string> ();
  332. foreach (var mi in UnderlyingType.GetMethods (bf)) {
  333. string name = null;
  334. if (mi.Name.StartsWith ("Get", StringComparison.Ordinal)) {
  335. if (mi.ReturnType == typeof (void))
  336. continue;
  337. var args = mi.GetParameters ();
  338. if (args.Length != 1)
  339. continue;
  340. name = mi.Name.Substring (3);
  341. gl.Add (name, mi);
  342. } else if (mi.Name.StartsWith ("Set", StringComparison.Ordinal)) {
  343. // looks like the return type is *ignored*
  344. //if (mi.ReturnType != typeof (void))
  345. // continue;
  346. var args = mi.GetParameters ();
  347. if (args.Length != 2)
  348. continue;
  349. name = mi.Name.Substring (3);
  350. sl.Add (name, mi);
  351. } else if (mi.Name.EndsWith ("Handler", StringComparison.Ordinal)) {
  352. var args = mi.GetParameters ();
  353. if (args.Length != 2)
  354. continue;
  355. if (mi.Name.StartsWith ("Add", StringComparison.Ordinal)) {
  356. name = mi.Name.Substring (3, mi.Name.Length - 3 - 7);
  357. al.Add (name, mi);
  358. }/* else if (mi.Name.StartsWith ("Remove", StringComparison.Ordinal)) {
  359. name = mi.Name.Substring (6, mi.Name.Length - 6 - 7);
  360. rl.Add (name, mi);
  361. }*/
  362. }
  363. if (name != null && !nl.Contains (name))
  364. nl.Add (name);
  365. }
  366. foreach (var name in nl) {
  367. MethodInfo m;
  368. var g = gl.TryGetValue (name, out m) ? m : null;
  369. var s = sl.TryGetValue (name, out m) ? m : null;
  370. if (g != null || s != null)
  371. yield return new XamlMember (name, g, s, SchemaContext);
  372. var a = al.TryGetValue (name, out m) ? m : null;
  373. //var r = rl.TryGetValue (name, out m) ? m : null;
  374. if (a != null)
  375. yield return new XamlMember (name, a, SchemaContext);
  376. }
  377. }
  378. static readonly XamlMember [] empty_array = new XamlMember [0];
  379. protected virtual IEnumerable<XamlMember> LookupAllMembers ()
  380. {
  381. if (UnderlyingType == null)
  382. return BaseType != null ? BaseType.GetAllMembers () : empty_array;
  383. if (all_members_cache == null) {
  384. all_members_cache = new List<XamlMember> (DoLookupAllMembers ());
  385. all_members_cache.Sort (TypeExtensionMethods.CompareMembers);
  386. }
  387. return all_members_cache;
  388. }
  389. List<XamlMember> all_members_cache;
  390. List<XamlMember> all_attachable_members_cache;
  391. IEnumerable<XamlMember> DoLookupAllMembers ()
  392. {
  393. // This is a hack that is likely required due to internal implementation difference in System.Uri. Our Uri has two readonly collection properties
  394. if (this == XamlLanguage.Uri)
  395. yield break;
  396. var bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
  397. foreach (var pi in UnderlyingType.GetProperties (bf)) {
  398. if (pi.Name.Contains ('.')) // exclude explicit interface implementations.
  399. continue;
  400. if (pi.CanRead && (pi.CanWrite || IsCollectionType (pi.PropertyType) || typeof (IXmlSerializable).IsAssignableFrom (pi.PropertyType)) && pi.GetIndexParameters ().Length == 0)
  401. yield return new XamlMember (pi, SchemaContext);
  402. }
  403. foreach (var ei in UnderlyingType.GetEvents (bf))
  404. yield return new XamlMember (ei, SchemaContext);
  405. }
  406. static bool IsPublicAccessor (MethodInfo mi)
  407. {
  408. return mi != null && mi.IsPublic;
  409. }
  410. bool IsCollectionType (Type type)
  411. {
  412. if (type == null)
  413. return false;
  414. var xt = SchemaContext.GetXamlType (type);
  415. return xt.LookupCollectionKind () != XamlCollectionKind.None;
  416. }
  417. protected virtual IList<XamlType> LookupAllowedContentTypes ()
  418. {
  419. // the actual implementation is very different from what is documented :(
  420. return null;
  421. /*
  422. var l = new List<XamlType> ();
  423. if (ContentWrappers != null)
  424. l.AddRange (ContentWrappers);
  425. if (ContentProperty != null)
  426. l.Add (ContentProperty.Type);
  427. if (ItemType != null)
  428. l.Add (ItemType);
  429. return l.Count > 0 ? l : null;
  430. */
  431. }
  432. protected virtual XamlMember LookupAttachableMember (string name)
  433. {
  434. return GetAllAttachableMembers ().FirstOrDefault (m => m.Name == name);
  435. }
  436. protected virtual XamlType LookupBaseType ()
  437. {
  438. if (base_type == null) {
  439. if (UnderlyingType == null)
  440. base_type = SchemaContext.GetXamlType (typeof (object));
  441. else
  442. base_type = type.BaseType == null || type.BaseType == typeof (object) ? null : SchemaContext.GetXamlType (type.BaseType);
  443. }
  444. return base_type;
  445. }
  446. // This implementation is not verified. (No place to use.)
  447. protected internal virtual XamlCollectionKind LookupCollectionKind ()
  448. {
  449. if (UnderlyingType == null)
  450. return BaseType != null ? BaseType.LookupCollectionKind () : XamlCollectionKind.None;
  451. if (type.IsArray)
  452. return XamlCollectionKind.Array;
  453. if (type.ImplementsAnyInterfacesOf (typeof (IDictionary), typeof (IDictionary<,>)))
  454. return XamlCollectionKind.Dictionary;
  455. if (type.ImplementsAnyInterfacesOf (typeof (IList), typeof (ICollection<>)))
  456. return XamlCollectionKind.Collection;
  457. return XamlCollectionKind.None;
  458. }
  459. protected virtual bool LookupConstructionRequiresArguments ()
  460. {
  461. if (UnderlyingType == null)
  462. return false;
  463. // not sure if it is required, but MemberDefinition return true while they are abstract and it makes no sense.
  464. if (UnderlyingType.IsAbstract)
  465. return true;
  466. // FIXME: probably some primitive types are treated as special.
  467. switch (Type.GetTypeCode (UnderlyingType)) {
  468. case TypeCode.String:
  469. return true;
  470. case TypeCode.Object:
  471. if (UnderlyingType == typeof (TimeSpan))
  472. return false;
  473. break;
  474. default:
  475. return false;
  476. }
  477. return UnderlyingType.GetConstructor (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null) == null;
  478. }
  479. protected virtual XamlMember LookupContentProperty ()
  480. {
  481. var a = this.GetCustomAttribute<ContentPropertyAttribute> ();
  482. return a != null && a.Name != null ? GetMember (a.Name) : null;
  483. }
  484. protected virtual IList<XamlType> LookupContentWrappers ()
  485. {
  486. if (GetCustomAttributeProvider () == null)
  487. return null;
  488. var arr = GetCustomAttributeProvider ().GetCustomAttributes (typeof (ContentWrapperAttribute), false);
  489. if (arr == null || arr.Length == 0)
  490. return null;
  491. var l = new XamlType [arr.Length];
  492. for (int i = 0; i < l.Length; i++)
  493. l [i] = SchemaContext.GetXamlType (((ContentWrapperAttribute) arr [i]).ContentWrapper);
  494. return l;
  495. }
  496. internal ICustomAttributeProvider GetCustomAttributeProvider ()
  497. {
  498. return LookupCustomAttributeProvider ();
  499. }
  500. protected internal virtual ICustomAttributeProvider LookupCustomAttributeProvider ()
  501. {
  502. return UnderlyingType;
  503. }
  504. protected virtual XamlValueConverter<XamlDeferringLoader> LookupDeferringLoader ()
  505. {
  506. throw new NotImplementedException ();
  507. }
  508. protected virtual XamlTypeInvoker LookupInvoker ()
  509. {
  510. return invoker;
  511. }
  512. protected virtual bool LookupIsAmbient ()
  513. {
  514. return this.GetCustomAttribute<AmbientAttribute> () != null;
  515. }
  516. // It is documented as if it were to reflect spec. section 5.2,
  517. // but the actual behavior shows it is *totally* wrong.
  518. // Here I have implemented this based on the nunit test results. sigh.
  519. protected virtual bool LookupIsConstructible ()
  520. {
  521. if (UnderlyingType == null)
  522. return true;
  523. if (IsMarkupExtension)
  524. return true;
  525. if (UnderlyingType.IsAbstract)
  526. return false;
  527. if (!IsNameValid)
  528. return false;
  529. return true;
  530. }
  531. protected virtual bool LookupIsMarkupExtension ()
  532. {
  533. return typeof (MarkupExtension).IsAssignableFrom (UnderlyingType);
  534. }
  535. protected virtual bool LookupIsNameScope ()
  536. {
  537. return typeof (INameScope).IsAssignableFrom (UnderlyingType);
  538. }
  539. protected virtual bool LookupIsNullable ()
  540. {
  541. return !type.IsValueType || type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>);
  542. }
  543. protected virtual bool LookupIsPublic ()
  544. {
  545. return underlying_type == null || underlying_type.IsPublic || underlying_type.IsNestedPublic;
  546. }
  547. protected virtual bool LookupIsUnknown ()
  548. {
  549. return UnderlyingType == null;
  550. }
  551. protected virtual bool LookupIsWhitespaceSignificantCollection ()
  552. {
  553. // probably for unknown types, it should preserve whitespaces.
  554. return IsUnknown || this.GetCustomAttribute<WhitespaceSignificantCollectionAttribute> () != null;
  555. }
  556. protected virtual bool LookupIsXData ()
  557. {
  558. return CanAssignTo (SchemaContext.GetXamlType (typeof (IXmlSerializable)));
  559. }
  560. protected virtual XamlType LookupItemType ()
  561. {
  562. if (IsArray)
  563. return new XamlType (type.GetElementType (), SchemaContext);
  564. if (IsDictionary) {
  565. if (!IsGeneric)
  566. return new XamlType (typeof (object), SchemaContext);
  567. return new XamlType (type.GetGenericArguments () [1], SchemaContext);
  568. }
  569. if (!IsCollection)
  570. return null;
  571. if (!IsGeneric)
  572. return new XamlType (typeof (object), SchemaContext);
  573. return new XamlType (type.GetGenericArguments () [0], SchemaContext);
  574. }
  575. protected virtual XamlType LookupKeyType ()
  576. {
  577. if (!IsDictionary)
  578. return null;
  579. if (!IsGeneric)
  580. return new XamlType (typeof (object), SchemaContext);
  581. return new XamlType (type.GetGenericArguments () [0], SchemaContext);
  582. }
  583. protected virtual XamlType LookupMarkupExtensionReturnType ()
  584. {
  585. var a = this.GetCustomAttribute<MarkupExtensionReturnTypeAttribute> ();
  586. return a != null ? new XamlType (a.ReturnType, SchemaContext) : null;
  587. }
  588. protected virtual XamlMember LookupMember (string name, bool skipReadOnlyCheck)
  589. {
  590. // FIXME: verify if this does not filter out events.
  591. return GetAllMembers ().FirstOrDefault (m => m.Name == name && (skipReadOnlyCheck || !m.IsReadOnly || m.Type.IsCollection || m.Type.IsDictionary || m.Type.IsArray));
  592. }
  593. protected virtual IList<XamlType> LookupPositionalParameters (int parameterCount)
  594. {
  595. if (UnderlyingType == null/* || !IsMarkupExtension*/) // see nunit tests...
  596. return null;
  597. // check if there is applicable ConstructorArgumentAttribute.
  598. // If there is, then return its type.
  599. if (parameterCount == 1) {
  600. foreach (var xm in GetAllMembers ()) {
  601. var ca = xm.GetCustomAttributeProvider ().GetCustomAttribute<ConstructorArgumentAttribute> (false);
  602. if (ca != null)
  603. return new XamlType [] {xm.Type};
  604. }
  605. }
  606. var methods = (from m in UnderlyingType.GetConstructors (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) where m.GetParameters ().Length == parameterCount select m).ToArray ();
  607. if (methods.Length == 1)
  608. return (from p in methods [0].GetParameters () select SchemaContext.GetXamlType (p.ParameterType)).ToArray ();
  609. if (SchemaContext.SupportMarkupExtensionsWithDuplicateArity)
  610. throw new NotSupportedException ("The default LookupPositionalParameters implementation does not allow duplicate arity of markup extensions");
  611. return null;
  612. }
  613. BindingFlags flags_get_static = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
  614. protected virtual EventHandler<XamlSetMarkupExtensionEventArgs> LookupSetMarkupExtensionHandler ()
  615. {
  616. var a = this.GetCustomAttribute<XamlSetMarkupExtensionAttribute> ();
  617. if (a == null)
  618. return null;
  619. var mi = type.GetMethod (a.XamlSetMarkupExtensionHandler, flags_get_static);
  620. if (mi == null)
  621. throw new ArgumentException ("Binding to XamlSetMarkupExtensionHandler failed");
  622. return (EventHandler<XamlSetMarkupExtensionEventArgs>) Delegate.CreateDelegate (typeof (EventHandler<XamlSetMarkupExtensionEventArgs>), mi);
  623. }
  624. protected virtual EventHandler<XamlSetTypeConverterEventArgs> LookupSetTypeConverterHandler ()
  625. {
  626. var a = this.GetCustomAttribute<XamlSetTypeConverterAttribute> ();
  627. if (a == null)
  628. return null;
  629. var mi = type.GetMethod (a.XamlSetTypeConverterHandler, flags_get_static);
  630. if (mi == null)
  631. throw new ArgumentException ("Binding to XamlSetTypeConverterHandler failed");
  632. return (EventHandler<XamlSetTypeConverterEventArgs>) Delegate.CreateDelegate (typeof (EventHandler<XamlSetTypeConverterEventArgs>), mi);
  633. }
  634. protected virtual bool LookupTrimSurroundingWhitespace ()
  635. {
  636. return this.GetCustomAttribute<TrimSurroundingWhitespaceAttribute> () != null;
  637. }
  638. protected virtual XamlValueConverter<TypeConverter> LookupTypeConverter ()
  639. {
  640. var t = UnderlyingType;
  641. if (t == null)
  642. return null;
  643. // equivalent to TypeExtension.
  644. // FIXME: not sure if it should be specially handled here.
  645. if (t == typeof (Type))
  646. t = typeof (TypeExtension);
  647. var a = GetCustomAttributeProvider ();
  648. var ca = a != null ? a.GetCustomAttribute<TypeConverterAttribute> (false) : null;
  649. if (ca != null)
  650. return SchemaContext.GetValueConverter<TypeConverter> (Type.GetType (ca.ConverterTypeName), this);
  651. if (t == typeof (object)) // This is a special case. ConverterType is null.
  652. return SchemaContext.GetValueConverter<TypeConverter> (null, this);
  653. // It's still not decent to check CollectionConverter.
  654. var tct = t.GetTypeConverter ().GetType ();
  655. if (tct != typeof (TypeConverter) && tct != typeof (CollectionConverter) && tct != typeof (ReferenceConverter))
  656. return SchemaContext.GetValueConverter<TypeConverter> (tct, this);
  657. return null;
  658. }
  659. protected virtual Type LookupUnderlyingType ()
  660. {
  661. return underlying_type;
  662. }
  663. protected virtual bool LookupUsableDuringInitialization ()
  664. {
  665. var a = this.GetCustomAttribute<UsableDuringInitializationAttribute> ();
  666. return a != null && a.Usable;
  667. }
  668. static XamlValueConverter<ValueSerializer> string_value_serializer;
  669. protected virtual XamlValueConverter<ValueSerializer> LookupValueSerializer ()
  670. {
  671. return LookupValueSerializer (this, GetCustomAttributeProvider ());
  672. }
  673. internal static XamlValueConverter<ValueSerializer> LookupValueSerializer (XamlType targetType, ICustomAttributeProvider provider)
  674. {
  675. if (provider == null)
  676. return null;
  677. var a = provider.GetCustomAttribute<ValueSerializerAttribute> (true);
  678. if (a != null)
  679. return new XamlValueConverter<ValueSerializer> (a.ValueSerializerType ?? Type.GetType (a.ValueSerializerTypeName), targetType);
  680. if (targetType.BaseType != null) {
  681. var ret = targetType.BaseType.LookupValueSerializer ();
  682. if (ret != null)
  683. return ret;
  684. }
  685. if (targetType.UnderlyingType == typeof (string)) {
  686. if (string_value_serializer == null)
  687. string_value_serializer = new XamlValueConverter<ValueSerializer> (typeof (StringValueSerializer), targetType);
  688. return string_value_serializer;
  689. }
  690. return null;
  691. }
  692. static string GetXamlName (Type type)
  693. {
  694. string n;
  695. if (!type.IsNestedPublic && !type.IsNestedAssembly && !type.IsNestedPrivate)
  696. n = type.Name;
  697. else
  698. n = GetXamlName (type.DeclaringType) + "+" + type.Name;
  699. if (type.IsGenericType && !type.ContainsGenericParameters) // the latter condition is to filter out "nested non-generic type within generic type".
  700. return n.Substring (0, n.IndexOf ('`'));
  701. else
  702. return n;
  703. }
  704. }
  705. }