2 // Copyright (C) 2010 Novell Inc. http://novell.com
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:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
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.
24 using System.Collections;
25 using System.Collections.Generic;
26 using System.ComponentModel;
27 using System.Globalization;
29 using System.Reflection;
31 using System.Xaml.Schema;
33 namespace System.Windows.Markup
35 [System.Runtime.CompilerServices.TypeForwardedFrom (Consts.AssemblyWindowsBase)]
36 public abstract class ValueSerializer
38 public static ValueSerializer GetSerializerFor (PropertyDescriptor descriptor)
40 return GetSerializerFor (descriptor, null);
43 public static ValueSerializer GetSerializerFor (Type type)
45 return GetSerializerFor (type, null);
49 public static ValueSerializer GetSerializerFor (PropertyDescriptor descriptor, IValueSerializerContext context)
51 if (descriptor == null)
52 throw new ArgumentNullException ("descriptor");
54 return context.GetValueSerializerFor (descriptor);
56 var tc = descriptor.Converter;
57 if (tc != null && tc.GetType () != typeof (TypeConverter))
58 return new TypeConverterValueSerializer (tc);
62 public static ValueSerializer GetSerializerFor (Type type, IValueSerializerContext context)
65 throw new ArgumentNullException ("type");
67 return context.GetValueSerializerFor (type);
69 // Standard MarkupExtensions are serialized without ValueSerializer.
70 if (typeof (MarkupExtension).IsAssignableFrom (type) && XamlLanguage.AllTypes.Any (x => x.UnderlyingType == type))
73 // DateTime is documented as special.
74 if (type == typeof (DateTime))
75 return new DateTimeValueSerializer ();
77 if (type == typeof (string))
78 return new StringValueSerializer ();
80 // FIXME: this is hack. The complete condition is fully documented at http://msdn.microsoft.com/en-us/library/ms590363.aspx
81 if (type.GetCustomAttribute<TypeConverterAttribute> (true) != null) {
82 var tc = TypeDescriptor.GetConverter (type);
83 if (tc != null && tc.GetType () != typeof (TypeConverter))
84 return new TypeConverterValueSerializer (tc);
87 // Undocumented, but System.Type seems also special. While other MarkupExtension returned types are not handled specially, this method returns a valid instance for System.Type. Note that it doesn't for TypeExtension.
88 if (type == typeof (Type))
89 // Since System.Type does not have a valid TypeConverter, I use TypeExtensionConverter (may sound funny considering the above notes!) for this serializer.
90 return new TypeValueSerializer ();
92 // Undocumented, but several primitive types get a valid serializer while it does not have TypeConverter.
93 switch (Type.GetTypeCode (type)) {
98 return new TypeConverterValueSerializer (TypeDescriptor.GetConverter (type));
101 // There is still exceptional type! TimeSpan. Why aren't they documented?
102 if (type == typeof (TimeSpan))
103 return new TypeConverterValueSerializer (TypeDescriptor.GetConverter (type));
110 public virtual bool CanConvertFromString (string value, IValueSerializerContext context)
115 public virtual bool CanConvertToString (object value, IValueSerializerContext context)
120 public virtual object ConvertFromString (string value, IValueSerializerContext context)
122 throw GetConvertFromException (value);
125 public virtual string ConvertToString (object value, IValueSerializerContext context)
127 throw GetConvertToException (value, typeof (string));
130 protected Exception GetConvertFromException (object value)
132 return new NotSupportedException (String.Format ("Conversion from string '{0}' is not supported", value));
135 protected Exception GetConvertToException (object value, Type destinationType)
137 return new NotSupportedException (String.Format ("Conversion from '{0}' to {1} is not supported", value != null ? value.GetType ().Name : "(null)", destinationType));
140 public virtual IEnumerable<Type> TypeReferences (object value, IValueSerializerContext context)
146 #region Internal implementations.
148 internal class StringValueSerializer : ValueSerializer
150 public override bool CanConvertFromString (string value, IValueSerializerContext context)
155 public override bool CanConvertToString (object value, IValueSerializerContext context)
160 public override object ConvertFromString (string value, IValueSerializerContext context)
165 public override string ConvertToString (object value, IValueSerializerContext context)
167 return (string) value;
170 public override IEnumerable<Type> TypeReferences (object value, IValueSerializerContext context)
172 throw new NotImplementedException ();
176 internal class TypeValueSerializer : ValueSerializer
178 TypeExtensionConverter txc = new TypeExtensionConverter ();
180 public override bool CanConvertFromString (string value, IValueSerializerContext context)
185 public override bool CanConvertToString (object value, IValueSerializerContext context)
190 public override object ConvertFromString (string value, IValueSerializerContext context)
192 var nsr = (IXamlNamespaceResolver) context.GetService (typeof (IXamlNamespaceResolver));
193 var scp = (IXamlSchemaContextProvider) context.GetService (typeof (IXamlSchemaContextProvider));
194 return scp.SchemaContext.GetXamlType (XamlTypeName.Parse (value, nsr)).UnderlyingType;
197 public override string ConvertToString (object value, IValueSerializerContext context)
199 return (string) txc.ConvertTo (context, CultureInfo.InvariantCulture, value, typeof (string));
202 public override IEnumerable<Type> TypeReferences (object value, IValueSerializerContext context)
204 throw new NotImplementedException ();
208 internal class TypeConverterValueSerializer : ValueSerializer
210 public TypeConverterValueSerializer (TypeConverter typeConverter)
217 public override bool CanConvertFromString (string value, IValueSerializerContext context)
219 return c.CanConvertFrom (context, typeof (string));
222 public override bool CanConvertToString (object value, IValueSerializerContext context)
224 return c.CanConvertTo (context, typeof (string));
227 public override object ConvertFromString (string value, IValueSerializerContext context)
229 return c.ConvertFromInvariantString (context, value);
232 public override string ConvertToString (object value, IValueSerializerContext context)
234 return value == null ? String.Empty : c.ConvertToInvariantString (context, value);
237 public override IEnumerable<Type> TypeReferences (object value, IValueSerializerContext context)
239 throw new NotImplementedException ();