PageRenderTime 115ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/mcs/class/System.Xaml/System.Xaml/TypeExtensionMethods.cs

https://github.com/pruiz/mono
C# | 302 lines | 234 code | 38 blank | 30 comment | 121 complexity | 89a5d0a9bc8f781e491a45cdd119acb3 MD5 | raw file
Possible License(s): 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.Globalization;
  28. using System.Linq;
  29. using System.Reflection;
  30. using System.Windows.Markup;
  31. using System.Xaml.Schema;
  32. namespace System.Xaml
  33. {
  34. static class TypeExtensionMethods
  35. {
  36. #region inheritance search and custom attribute provision
  37. public static T GetCustomAttribute<T> (this ICustomAttributeProvider type, bool inherit) where T : Attribute
  38. {
  39. foreach (var a in type.GetCustomAttributes (typeof (T), inherit))
  40. return (T) (object) a;
  41. return null;
  42. }
  43. public static T GetCustomAttribute<T> (this XamlType type) where T : Attribute
  44. {
  45. if (type.UnderlyingType == null)
  46. return null;
  47. T ret = type.GetCustomAttributeProvider ().GetCustomAttribute<T> (true);
  48. if (ret != null)
  49. return ret;
  50. if (type.BaseType != null)
  51. return type.BaseType.GetCustomAttribute<T> ();
  52. return null;
  53. }
  54. public static bool ImplementsAnyInterfacesOf (this Type type, params Type [] definitions)
  55. {
  56. return definitions.Any (t => ImplementsInterface (type, t));
  57. }
  58. public static bool ImplementsInterface (this Type type, Type definition)
  59. {
  60. if (type == null)
  61. throw new ArgumentNullException ("type");
  62. if (definition == null)
  63. throw new ArgumentNullException ("definition");
  64. if (type == definition)
  65. return true;
  66. if (type.IsGenericType && type.GetGenericTypeDefinition () == definition)
  67. return true;
  68. foreach (var iface in type.GetInterfaces ())
  69. if (iface == definition || (iface.IsGenericType && iface.GetGenericTypeDefinition () == definition))
  70. return true;
  71. return false;
  72. }
  73. #endregion
  74. #region type conversion and member value retrieval
  75. static readonly NullExtension null_value = new NullExtension ();
  76. public static object GetExtensionWrapped (object o)
  77. {
  78. // FIXME: should this manually checked, or is there any way to automate it?
  79. // Also XamlSchemaContext might be involved but this method signature does not take it consideration.
  80. if (o == null)
  81. return null_value;
  82. if (o is Array)
  83. return new ArrayExtension ((Array) o);
  84. if (o is Type)
  85. return new TypeExtension ((Type) o);
  86. return o;
  87. }
  88. public static string GetStringValue (XamlType xt, XamlMember xm, object obj, IValueSerializerContext vsctx)
  89. {
  90. if (obj == null)
  91. return String.Empty;
  92. if (obj is Type)
  93. return new XamlTypeName (xt.SchemaContext.GetXamlType ((Type) obj)).ToString (vsctx != null ? vsctx.GetService (typeof (INamespacePrefixLookup)) as INamespacePrefixLookup : null);
  94. var vs = (xm != null ? xm.ValueSerializer : null) ?? xt.ValueSerializer;
  95. if (vs != null)
  96. return vs.ConverterInstance.ConvertToString (obj, vsctx);
  97. // FIXME: does this make sense?
  98. var vc = (xm != null ? xm.TypeConverter : null) ?? xt.TypeConverter;
  99. var tc = vc != null ? vc.ConverterInstance : null;
  100. if (tc != null && typeof (string) != null && tc.CanConvertTo (vsctx, typeof (string)))
  101. return (string) tc.ConvertTo (vsctx, CultureInfo.InvariantCulture, obj, typeof (string));
  102. if (obj is string || obj == null)
  103. return (string) obj;
  104. throw new InvalidCastException (String.Format ("Cannot cast object '{0}' to string", obj.GetType ()));
  105. }
  106. public static TypeConverter GetTypeConverter (this Type type)
  107. {
  108. return TypeDescriptor.GetConverter (type);
  109. }
  110. // FIXME: I want this to cover all the existing types and make it valid in both MOBILE and !MOBILE.
  111. class ConvertibleTypeConverter<T> : TypeConverter
  112. {
  113. Type type;
  114. public ConvertibleTypeConverter ()
  115. {
  116. this.type = typeof (T);
  117. }
  118. public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType)
  119. {
  120. return sourceType == typeof (string);
  121. }
  122. public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
  123. {
  124. return destinationType == typeof (string);
  125. }
  126. public override object ConvertFrom (ITypeDescriptorContext context, CultureInfo culture, object value)
  127. {
  128. if (type == typeof (DateTime))
  129. return System.Xml.XmlConvert.ToDateTime ((string) value, System.Xml.XmlDateTimeSerializationMode.Unspecified);
  130. return ((IConvertible) value).ToType (type, CultureInfo.InvariantCulture);
  131. }
  132. public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
  133. {
  134. if (value is DateTime)
  135. return System.Xml.XmlConvert.ToString ((DateTime) value);
  136. return ((IConvertible) value).ToType (destinationType, CultureInfo.InvariantCulture);
  137. }
  138. }
  139. #endregion
  140. public static bool IsContentValue (this XamlMember member, IValueSerializerContext vsctx)
  141. {
  142. if (member == XamlLanguage.Initialization)
  143. return true;
  144. if (member == XamlLanguage.PositionalParameters || member == XamlLanguage.Arguments)
  145. return false; // it's up to the argument (no need to check them though, as IList<object> is not of value)
  146. if (member.TypeConverter != null && member.TypeConverter.ConverterInstance != null && member.TypeConverter.ConverterInstance.CanConvertTo (vsctx, typeof (string)))
  147. return true;
  148. return IsContentValue (member.Type,vsctx);
  149. }
  150. public static bool IsContentValue (this XamlType type, IValueSerializerContext vsctx)
  151. {
  152. if (type.TypeConverter != null && type.TypeConverter.ConverterInstance != null && type.TypeConverter.ConverterInstance.CanConvertTo (vsctx, typeof (string)))
  153. return true;
  154. return false;
  155. }
  156. public static bool ListEquals (this IList<XamlType> a1, IList<XamlType> a2)
  157. {
  158. if (a1 == null || a1.Count == 0)
  159. return a2 == null || a2.Count == 0;
  160. if (a2 == null || a2.Count == 0)
  161. return false;
  162. if (a1.Count != a2.Count)
  163. return false;
  164. for (int i = 0; i < a1.Count; i++)
  165. if (a1 [i] != a2 [i])
  166. return false;
  167. return true;
  168. }
  169. public static bool HasPositionalParameters (this XamlType type, IValueSerializerContext vsctx)
  170. {
  171. // FIXME: find out why only TypeExtension and StaticExtension yield this directive. Seealso XamlObjectReaderTest.Read_CustomMarkupExtension*()
  172. return type == XamlLanguage.Type ||
  173. type == XamlLanguage.Static ||
  174. ExaminePositionalParametersApplicable (type, vsctx) && type.ConstructionRequiresArguments;
  175. }
  176. static bool ExaminePositionalParametersApplicable (this XamlType type, IValueSerializerContext vsctx)
  177. {
  178. if (!type.IsMarkupExtension || type.UnderlyingType == null)
  179. return false;
  180. var args = type.GetSortedConstructorArguments ();
  181. if (args == null)
  182. return false;
  183. foreach (var arg in args)
  184. if (arg.Type != null && !arg.Type.IsContentValue (vsctx))
  185. return false;
  186. Type [] argTypes = (from arg in args select arg.Type.UnderlyingType).ToArray ();
  187. if (argTypes.Any (at => at == null))
  188. return false;
  189. var ci = type.UnderlyingType.GetConstructor (argTypes);
  190. return ci != null;
  191. }
  192. public static IEnumerable<XamlMember> GetConstructorArguments (this XamlType type)
  193. {
  194. return type.GetAllMembers ().Where (m => m.UnderlyingMember != null && m.GetCustomAttributeProvider ().GetCustomAttribute<ConstructorArgumentAttribute> (false) != null);
  195. }
  196. public static IEnumerable<XamlMember> GetSortedConstructorArguments (this XamlType type)
  197. {
  198. var args = type.GetConstructorArguments ().ToArray ();
  199. foreach (var ci in type.UnderlyingType.GetConstructors ().Where (c => c.GetParameters ().Length == args.Length)) {
  200. var pis = ci.GetParameters ();
  201. if (args.Length != pis.Length)
  202. continue;
  203. bool mismatch = false;
  204. foreach (var pi in pis)
  205. for (int i = 0; i < args.Length; i++)
  206. if (!args.Any (a => a.ConstructorArgumentName () == pi.Name))
  207. mismatch = true;
  208. if (mismatch)
  209. continue;
  210. return args.OrderBy (c => pis.FindParameterWithName (c.ConstructorArgumentName ()).Position);
  211. }
  212. return null;
  213. }
  214. static ParameterInfo FindParameterWithName (this IEnumerable<ParameterInfo> pis, string name)
  215. {
  216. return pis.FirstOrDefault (pi => pi.Name == name);
  217. }
  218. public static string ConstructorArgumentName (this XamlMember xm)
  219. {
  220. var caa = xm.GetCustomAttributeProvider ().GetCustomAttribute<ConstructorArgumentAttribute> (false);
  221. return caa.ArgumentName;
  222. }
  223. internal static int CompareMembers (XamlMember m1, XamlMember m2)
  224. {
  225. // ConstructorArguments and PositionalParameters go first.
  226. if (m1 == XamlLanguage.PositionalParameters)
  227. return -1;
  228. if (m2 == XamlLanguage.PositionalParameters)
  229. return 1;
  230. if (m1.IsConstructorArgument ()) {
  231. if (!m2.IsConstructorArgument ())
  232. return -1;
  233. }
  234. else if (m2.IsConstructorArgument ())
  235. return 1;
  236. // ContentProperty is returned at last.
  237. if (m1.DeclaringType != null && m1.DeclaringType.ContentProperty == m1)
  238. return 1;
  239. if (m2.DeclaringType != null && m2.DeclaringType.ContentProperty == m2)
  240. return -1;
  241. // then, compare names.
  242. return String.CompareOrdinal (m1.Name, m2.Name);
  243. }
  244. internal static bool IsConstructorArgument (this XamlMember xm)
  245. {
  246. var ap = xm.GetCustomAttributeProvider ();
  247. return ap != null && ap.GetCustomAttributes (typeof (ConstructorArgumentAttribute), false).Length > 0;
  248. }
  249. internal static string GetInternalXmlName (this XamlMember xm)
  250. {
  251. return xm.IsAttachable ? String.Concat (xm.DeclaringType.GetInternalXmlName (), ".", xm.Name) : xm.Name;
  252. }
  253. #if DOTNET
  254. internal static ICustomAttributeProvider GetCustomAttributeProvider (this XamlType type)
  255. {
  256. return type.UnderlyingType;
  257. }
  258. internal static ICustomAttributeProvider GetCustomAttributeProvider (this XamlMember member)
  259. {
  260. return member.UnderlyingMember;
  261. }
  262. #endif
  263. }
  264. }