diff --git a/UnitsNet.Tests/Helpers/TypeDescriptorContext.cs b/UnitsNet.Tests/Helpers/TypeDescriptorContext.cs
new file mode 100644
index 0000000000..a4675599c3
--- /dev/null
+++ b/UnitsNet.Tests/Helpers/TypeDescriptorContext.cs
@@ -0,0 +1,80 @@
+// Licensed under MIT No Attribution, see LICENSE file at the root.
+// Copyright 2013 Andreas Gullberg Larsen (andreas.larsen84@gmail.com). Maintained at https://github.com/angularsen/UnitsNet.
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Text;
+
+namespace UnitsNet.Tests.Helpers
+{
+ ///
+ /// Is used to imitate e property with attributes
+ ///
+ public class TypeDescriptorContext : ITypeDescriptorContext
+ {
+ public class PropertyDescriptor_ : PropertyDescriptor
+ {
+ public PropertyDescriptor_(string name, Attribute[] attributes) : base(name, attributes)
+ {
+ }
+
+ public override Type ComponentType => throw new NotImplementedException();
+
+ public override bool IsReadOnly => throw new NotImplementedException();
+
+ public override Type PropertyType => throw new NotImplementedException();
+
+ public override bool CanResetValue(object component)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override object GetValue(object component)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void ResetValue(object component)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void SetValue(object component, object value)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override bool ShouldSerializeValue(object component)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public TypeDescriptorContext(string name, Attribute[] attributes)
+ {
+ PropertyDescriptor = new PropertyDescriptor_(name, attributes);
+ }
+
+ public IContainer Container => throw new NotImplementedException();
+
+ public object Instance => throw new NotImplementedException();
+
+ public PropertyDescriptor PropertyDescriptor { get; set; }
+
+ public object GetService(Type serviceType)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void OnComponentChanged()
+ {
+ throw new NotImplementedException();
+ }
+
+ public bool OnComponentChanging()
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/UnitsNet.Tests/QuantityTypeConverterTest.cs b/UnitsNet.Tests/QuantityTypeConverterTest.cs
new file mode 100644
index 0000000000..94dbac7d04
--- /dev/null
+++ b/UnitsNet.Tests/QuantityTypeConverterTest.cs
@@ -0,0 +1,315 @@
+// Licensed under MIT No Attribution, see LICENSE file at the root.
+// Copyright 2013 Andreas Gullberg Larsen (andreas.larsen84@gmail.com). Maintained at https://github.com/angularsen/UnitsNet.
+
+using System;
+using System.ComponentModel;
+using System.Globalization;
+using System.Reflection;
+using UnitsNet.Tests.Helpers;
+using Xunit;
+
+namespace UnitsNet.Tests
+{
+ public class QuantityTypeConverterTest
+ {
+ // https://stackoverflow.com/questions/3612909/why-is-this-typeconverter-not-working
+ private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
+ {
+ AppDomain domain = (AppDomain)sender;
+ foreach (Assembly asm in domain.GetAssemblies())
+ {
+ if (asm.FullName == args.Name)
+ {
+ return asm;
+ }
+ }
+ return null;
+ }
+
+ static QuantityTypeConverterTest()
+ {
+ // NOTE: After this, you can use your TypeConverter.
+ AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
+ }
+
+ ///
+ /// Is used for tests that are culture dependent
+ ///
+ private static CultureInfo culture = CultureInfo.GetCultureInfo("en-US");
+
+ [Theory]
+ [InlineData(typeof(string), true)]
+ [InlineData(typeof(double), false)]
+ [InlineData(typeof(object), false)]
+ [InlineData(typeof(float), false)]
+ [InlineData(typeof(Length), false)]
+ public void CanConvertFrom_GivenSomeTypes(Type value, bool expectedResult)
+ {
+ var converter = new QuantityTypeConverter();
+
+ bool canConvertFrom = converter.CanConvertFrom(value);
+
+ Assert.Equal(expectedResult, canConvertFrom);
+ }
+
+ [Theory]
+ [InlineData(typeof(string), true)]
+ [InlineData(typeof(double), false)]
+ [InlineData(typeof(object), false)]
+ [InlineData(typeof(float), false)]
+ [InlineData(typeof(Length), false)]
+ public void CanConvertTo_GivenSomeTypes(Type value, bool expectedResult)
+ {
+ var converter = new QuantityTypeConverter();
+
+ bool canConvertTo = converter.CanConvertTo(value);
+
+ Assert.Equal(expectedResult, canConvertTo);
+ }
+
+ [Theory]
+ [InlineData("1mm", 1, Units.LengthUnit.Millimeter)]
+ [InlineData("1m", 1, Units.LengthUnit.Meter)]
+ [InlineData("1", 1, Units.LengthUnit.Meter)]
+ [InlineData("1km", 1, Units.LengthUnit.Kilometer)]
+ public void ConvertFrom_GivenQuantityStringAndContextWithNoAttributes_ReturnsQuantityWithBaseUnitIfNotSpecified(string str, double expectedValue, Enum expectedUnit)
+ {
+ var converter = new QuantityTypeConverter();
+ ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { });
+
+ var convertedValue = (Length)converter.ConvertFrom(context, culture, str);
+
+ Assert.Equal(expectedValue, convertedValue.Value);
+ Assert.Equal(expectedUnit, convertedValue.Unit);
+ }
+
+ [Theory]
+ [InlineData("1mm", 1, Units.LengthUnit.Millimeter)]
+ [InlineData("1m", 1, Units.LengthUnit.Meter)]
+ [InlineData("1", 1, Units.LengthUnit.Centimeter)]
+ [InlineData("1km", 1, Units.LengthUnit.Kilometer)]
+ public void ConvertFrom_GivenQuantityStringAndContextWithDefaultUnitAttribute_ReturnsQuantityWithGivenDefaultUnitIfNotSpecified(string str, double expectedValue, Enum expectedUnit)
+ {
+ var converter = new QuantityTypeConverter();
+ ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[]
+ {
+ new DefaultUnitAttribute(Units.LengthUnit.Centimeter)
+ });
+
+ var convertedValue = (Length)converter.ConvertFrom(context, culture, str);
+
+ Assert.Equal(expectedValue, convertedValue.Value);
+ Assert.Equal(expectedUnit, convertedValue.Unit);
+ }
+
+ [Theory]
+ [InlineData("1mm", 0.001, Units.LengthUnit.Meter)]
+ [InlineData("1m", 1, Units.LengthUnit.Meter)]
+ [InlineData("1", 0.01, Units.LengthUnit.Meter)]
+ [InlineData("1km", 1000, Units.LengthUnit.Meter)]
+ public void ConvertFrom_GivenQuantityStringAndContextWithDefaultUnitAndConvertToUnitAttributes_ReturnsQuantityConvertedToUnit(string str, double expectedValue, Enum expectedUnit)
+ {
+ var converter = new QuantityTypeConverter();
+ ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[]
+ {
+ new DefaultUnitAttribute(Units.LengthUnit.Centimeter),
+ new ConvertToUnitAttribute(Units.LengthUnit.Meter)
+ });
+
+ var convertedValue = (Length)converter.ConvertFrom(context, culture, str);
+
+ Assert.Equal(expectedValue, convertedValue.Value);
+ Assert.Equal(expectedUnit, convertedValue.Unit);
+ }
+
+ [Fact]
+ public void ConvertFrom_GivenEmptyString_ThrowsNotSupportedException()
+ {
+ var converter = new QuantityTypeConverter();
+ ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { });
+
+ Assert.Throws(() => converter.ConvertFrom(context, culture, ""));
+ }
+
+ [Fact]
+ public void ConvertFrom_GivenWrongQuantity_ThrowsArgumentException()
+ {
+ var converter = new QuantityTypeConverter();
+ ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { });
+
+ Assert.Throws(() => converter.ConvertFrom(context, culture, "1m^2"));
+ }
+
+ [Theory]
+ [InlineData(typeof(Length))]
+ [InlineData(typeof(IQuantity))]
+ [InlineData(typeof(object))]
+ public void ConvertTo_GivenWrongType_ThrowsNotSupportedException(Type value)
+ {
+ var converter = new QuantityTypeConverter();
+ ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { });
+ Length length = Length.FromMeters(1);
+
+ Assert.Throws(() => converter.ConvertTo(length, value));
+ }
+
+ [Fact]
+ public void ConvertTo_GivenStringType_ReturnsQuantityString()
+ {
+ var converter = new QuantityTypeConverter();
+ ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { });
+ Length length = Length.FromMeters(1);
+
+ string convertedQuantity = (string)converter.ConvertTo(length, typeof(string));
+
+ Assert.Equal("1 m", convertedQuantity);
+ }
+
+ [Fact]
+ public void ConvertTo_GivenSomeQuantitysAndContextWithNoAttributes_ReturnsQuantityStringInUnitOfQuantity()
+ {
+ var converter = new QuantityTypeConverter();
+ ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { });
+ Length length = Length.FromMeters(1);
+
+ string convertedQuantity = (string)converter.ConvertTo(context, culture, length, typeof(string));
+
+ Assert.Equal("1 m", convertedQuantity);
+ }
+
+ [Fact]
+ public void ConvertTo_TestDisplayAsFormatting_ReturnsQuantityStringWithDisplayUnitDefaultFormating()
+ {
+ var converter = new QuantityTypeConverter();
+ ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[]
+ {
+ new DisplayAsUnitAttribute(Units.LengthUnit.Decimeter)
+ });
+ Length length = Length.FromMeters(1);
+
+ string convertedQuantity = (string)converter.ConvertTo(context, culture, length, typeof(string));
+
+ Assert.Equal("10 dm", convertedQuantity);
+ }
+
+ [Fact]
+ public void ConvertTo_TestDisplayAsFormatting_ReturnsQuantityStringWithDisplayUnitFormateAsValueOnly()
+ {
+ var converter = new QuantityTypeConverter();
+ ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[]
+ {
+ new DisplayAsUnitAttribute(Units.LengthUnit.Decimeter, "v")
+ });
+ Length length = Length.FromMeters(1);
+
+ string convertedQuantity = (string)converter.ConvertTo(context, culture, length, typeof(string));
+
+ Assert.Equal("10", convertedQuantity);
+ }
+
+ [Fact]
+ public void ConvertTo_TestDisplayAsFormattingWithoutDefinedUnit_ReturnsQuantityStringWithQuantetiesUnitAndFormatedAsValueOnly()
+ {
+ var converter = new QuantityTypeConverter();
+ ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[]
+ {
+ new DisplayAsUnitAttribute(null, "v")
+ });
+ Length length = Length.FromMeters(1);
+
+ string convertedQuantity = (string)converter.ConvertTo(context, culture, length, typeof(string));
+
+ Assert.Equal("1", convertedQuantity);
+ }
+
+ [Fact]
+ public void ConvertTo_GivenSomeQuantitysAndContextWithDisplayAsUnitAttributes_ReturnsQuantityStringInSpecifiedDisplayUnit()
+ {
+ var converter = new QuantityTypeConverter();
+ ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[]
+ {
+ new DisplayAsUnitAttribute(Units.LengthUnit.Decimeter)
+ });
+ Length length = Length.FromMeters(1);
+
+ string convertedQuantityDefaultCulture = (string)converter.ConvertTo(length, typeof(string));
+ string convertedQuantitySpecificCulture = (string)converter.ConvertTo(context, culture, length, typeof(string));
+
+ Assert.Equal("1 m", convertedQuantityDefaultCulture);
+ Assert.Equal("10 dm", convertedQuantitySpecificCulture);
+ }
+
+ [Fact]
+ public void ConvertFrom_GivenDefaultUnitAttributeWithWrongUnitType_ThrowsArgumentException()
+ {
+ var converter = new QuantityTypeConverter();
+ ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[]
+ {
+ new DefaultUnitAttribute(Units.VolumeUnit.CubicMeter)
+ });
+
+ Assert.Throws(() => converter.ConvertFrom(context, culture, "1"));
+ }
+
+ [Fact]
+ public void ConvertFrom_GivenStringWithPower_1()
+ {
+ var converter = new QuantityTypeConverter();
+ ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { });
+
+ Assert.Equal(Length.FromMeters(1), converter.ConvertFrom(context, culture, "1m"));
+ Assert.Equal(Length.FromMeters(1), converter.ConvertFrom(context, culture, "1m^1"));
+ }
+
+ [Fact]
+ public void ConvertFrom_GivenStringWithPower_2()
+ {
+ var converter = new QuantityTypeConverter();
+ ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { });
+
+ Assert.Equal(Area.FromSquareMeters(1), converter.ConvertFrom(context, culture, "1m²"));
+ Assert.Equal(Area.FromSquareMeters(1), converter.ConvertFrom(context, culture, "1m^2"));
+ }
+
+ [Fact]
+ public void ConvertFrom_GivenStringWithPower_3()
+ {
+ var converter = new QuantityTypeConverter();
+ ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { });
+
+ Assert.Equal(Volume.FromCubicMeters(1), converter.ConvertFrom(context, culture, "1m³"));
+ Assert.Equal(Volume.FromCubicMeters(1), converter.ConvertFrom(context, culture, "1m^3"));
+ }
+
+ [Fact]
+ public void ConvertFrom_GivenStringWithPower_4()
+ {
+ var converter = new QuantityTypeConverter();
+ ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { });
+
+ Assert.Equal(AreaMomentOfInertia.FromMetersToTheFourth(1), converter.ConvertFrom(context, culture, "1m⁴"));
+ Assert.Equal(AreaMomentOfInertia.FromMetersToTheFourth(1), converter.ConvertFrom(context, culture, "1m^4"));
+ }
+
+ [Fact]
+ public void ConvertFrom_GivenStringWithPower_minus1()
+ {
+ var converter = new QuantityTypeConverter();
+ ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { });
+
+ Assert.Equal(CoefficientOfThermalExpansion.FromInverseKelvin(1), converter.ConvertFrom(context, culture, "1K⁻¹"));
+ Assert.Equal(CoefficientOfThermalExpansion.FromInverseKelvin(1), converter.ConvertFrom(context, culture, "1K^-1"));
+ }
+
+ [Fact]
+ public void ConvertFrom_GivenStringWithPower_minus2()
+ {
+ var converter = new QuantityTypeConverter();
+ ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { });
+
+ Assert.Equal(MassFlux.FromKilogramsPerSecondPerSquareMeter(1), converter.ConvertFrom(context, culture, "1kg·s⁻¹·m⁻²"));
+ Assert.Equal(MassFlux.FromKilogramsPerSecondPerSquareMeter(1), converter.ConvertFrom(context, culture, "1kg·s^-1·m^-2"));
+ Assert.Equal(MassFlux.FromKilogramsPerSecondPerSquareMeter(1), converter.ConvertFrom(context, culture, "1kg*s^-1*m^-2"));
+ }
+ }
+}
diff --git a/UnitsNet/QuantityTypeConverter.cs b/UnitsNet/QuantityTypeConverter.cs
new file mode 100644
index 0000000000..0b0ab77a77
--- /dev/null
+++ b/UnitsNet/QuantityTypeConverter.cs
@@ -0,0 +1,263 @@
+// Licensed under MIT No Attribution, see LICENSE file at the root.
+// Copyright 2013 Andreas Gullberg Larsen (andreas.larsen84@gmail.com). Maintained at https://github.com/angularsen/UnitsNet.
+
+using System;
+using System.ComponentModel;
+using System.Globalization;
+
+namespace UnitsNet
+{
+ ///
+ /// Is the base class for all attributes that are related to
+ ///
+ [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
+ public abstract class UnitAttributeBase : Attribute
+ {
+ ///
+ /// The unit enum type, such as
+ ///
+ public Enum UnitType { get; set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ public UnitAttributeBase(object unitType)
+ {
+ UnitType = unitType as Enum;
+ }
+ }
+
+ ///
+ /// This attribute defines the default Unit to use if the string to convert only consists of digits
+ ///
+ public class DefaultUnitAttribute : UnitAttributeBase
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The unit the quantity gets when the string parsing dose only consist of digits
+ public DefaultUnitAttribute(object unitType) : base(unitType) { }
+ }
+
+ ///
+ /// This attribute defines the Unit the quantity is converted to after it has been parsed.
+ ///
+ public class ConvertToUnitAttribute : DefaultUnitAttribute
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The unit the quantity is converted to when parsing from string
+ public ConvertToUnitAttribute(object unitType) : base(unitType) { }
+ }
+
+ ///
+ /// This attribute defines the unit the quantity has when converting to string
+ ///
+ public class DisplayAsUnitAttribute : DefaultUnitAttribute
+ {
+ ///
+ /// The formating used when the quantity is converted to string. See
+ ///
+ public string Format { get; set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The unit the quantity should be displayed in
+ /// Formating string
+ public DisplayAsUnitAttribute(object unitType, string format = "") : base(unitType)
+ {
+ Format = format;
+ }
+ }
+
+ ///
+ ///
+ /// Converts between IQuantity and string.
+ /// Implements a TypeConverter for IQuantitys. This allows eg the PropertyGrid to read and write properties of type IQuantity.
+ ///
+ /// For basic understanding of TypeConverters consult the .NET documentation.
+ ///
+ /// Quantity value type, such as or .
+ ///
+ ///
+ /// When a string is converted a Quantity the unit given by the string is used.
+ /// When no unit is given by the string the base unit is used.
+ /// The base unit can be overwritten by use of the .
+ /// The converted Quantity can be forced to be in a certain unit by use of the .
+ ///
+ ///
+ /// The displayed unit can be forced to a certain unit by use of the .
+ /// The provides the possibility to format the displayed Quantity.
+ ///
+ ///
+ ///
+ /// These examples show how to use this TypeConverter.
+ ///
+ ///
+ /// [TypeConverter(typeof(UnitsNetTypeConverter{Length}))]
+ /// Units.Length PropertyName { get; set; }
+ ///
+ ///
+ ///
+ /// [DisplayAsUnit(UnitsNet.Units.LengthUnit.Meter)]
+ /// [TypeConverter(typeof(UnitsNetTypeConverter{Length}))]
+ /// Units.Length Length { get; set; }
+ ///
+ ///
+ ///
+ /// [DisplayAsUnit(UnitsNet.Units.LengthUnit.Meter, "g")]
+ /// [TypeConverter(typeof(UnitsNetTypeConverter{Length}))]
+ /// Units.Length Length { get; set; }
+ ///
+ ///
+ ///
+ /// [ConvertToUnitAttribute(UnitsNet.Units.LengthUnit.Meter)]
+ /// [TypeConverter(typeof(UnitsNetTypeConverter{Length}))]
+ /// Units.Length Length { get; set; }
+ ///
+ ///
+ ///
+ /// [DefaultUnitAttribute(UnitsNet.Units.LengthUnit.Meter)]
+ /// [TypeConverter(typeof(UnitsNetTypeConverter{Length}))]
+ /// Units.Length Length { get; set; }
+ ///
+ ///
+ public class QuantityTypeConverter : TypeConverter where TQuantity : IQuantity
+ {
+ ///
+ /// Returns true if sourceType if of type
+ ///
+ /// An that provides a format context.
+ /// A that represents the type you want to convert from.
+ /// true if this converter can perform the conversion; otherwise, false.
+ public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
+ {
+ return (sourceType == typeof(string)) || base.CanConvertFrom(context, sourceType);
+ }
+
+ private static TAttribute GetAttribute(ITypeDescriptorContext context) where TAttribute : UnitAttributeBase
+ {
+ TAttribute attribute = null;
+ AttributeCollection ua = context?.PropertyDescriptor.Attributes;
+
+ attribute = (TAttribute)ua?[typeof(TAttribute)];
+
+ if (attribute != null)
+ {
+ QuantityType expected = default(TQuantity).Type;
+ QuantityType actual = QuantityType.Undefined;
+
+ if (attribute.UnitType != null) actual = Quantity.From(1, attribute.UnitType).Type;
+ if (actual != QuantityType.Undefined && expected != actual)
+ {
+ throw new ArgumentException($"The specified UnitType:'{attribute.UnitType}' dose not match QuantityType:'{expected}'");
+ }
+ }
+
+ return attribute;
+ }
+
+ ///
+ /// Converts the given object, when it is of type to the type of this converter, using the specified context and culture information.
+ ///
+ /// An System.ComponentModel.ITypeDescriptorContext that provides a format context.
+ /// The System.Globalization.CultureInfo to use as the current culture.
+ /// The System.Object to convert.
+ /// An object.
+ /// The conversion cannot be performed.
+ /// Unit value is not a know unit enum type.
+ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
+ {
+ string stringValue = value as string;
+ object result = null;
+
+ if (!string.IsNullOrEmpty(stringValue))
+ {
+ if (double.TryParse(stringValue, NumberStyles.Any, culture, out double dvalue))
+ {
+ DefaultUnitAttribute defaultUnit = GetAttribute(context) ?? new DefaultUnitAttribute(default(TQuantity).Unit);
+
+ result = Quantity.From(dvalue, defaultUnit.UnitType);
+ }
+ else
+ {
+ // TODO this should not be part of QuantityTypeConverter. it should rather be part of the parse function
+ stringValue = stringValue.Replace("^-9", "⁻⁹");
+ stringValue = stringValue.Replace("^-8", "⁻⁸");
+ stringValue = stringValue.Replace("^-7", "⁻⁷");
+ stringValue = stringValue.Replace("^-6", "⁻⁶");
+ stringValue = stringValue.Replace("^-5", "⁻⁵");
+ stringValue = stringValue.Replace("^-4", "⁻⁴");
+ stringValue = stringValue.Replace("^-3", "⁻³");
+ stringValue = stringValue.Replace("^-2", "⁻²");
+ stringValue = stringValue.Replace("^-1", "⁻¹");
+ stringValue = stringValue.Replace("^1", "");
+ stringValue = stringValue.Replace("^2", "²");
+ stringValue = stringValue.Replace("^3", "³");
+ stringValue = stringValue.Replace("^4", "⁴");
+ stringValue = stringValue.Replace("^5", "⁵");
+ stringValue = stringValue.Replace("^6", "⁶");
+ stringValue = stringValue.Replace("^7", "⁷");
+ stringValue = stringValue.Replace("^8", "⁸");
+ stringValue = stringValue.Replace("^9", "⁹");
+ stringValue = stringValue.Replace("*", "·");
+
+ result = Quantity.Parse(culture, typeof(TQuantity), stringValue);
+ }
+
+ ConvertToUnitAttribute convertToUnit = GetAttribute(context);
+ if (convertToUnit != null)
+ {
+ result = ((IQuantity)result).ToUnit(convertToUnit.UnitType);
+ }
+ }
+
+ return result ?? base.ConvertFrom(context, culture, value);
+ }
+
+ /// Returns true whether this converter can convert the to string, using the specified context.
+ /// true if this converter can perform the conversion; otherwise, false.
+ /// An that provides a format context.
+ /// A that represents the type you want to convert to.
+ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+ {
+ return (destinationType == typeof(string)) || base.CanConvertTo(context, destinationType);
+ }
+
+ /// Converts the given object to , using the specified context and culture information.
+ /// An that represents the converted value.
+ /// An that provides a format context.
+ /// A . If null is passed, the current culture is assumed.
+ /// The to convert.
+ /// The to convert the parameter to.
+ /// The parameter is null.
+ /// The conversion cannot be performed.
+ public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
+ {
+ IQuantity qvalue = value as IQuantity;
+ object result = null;
+ DisplayAsUnitAttribute displayAsUnit = GetAttribute(context);
+
+ if (destinationType == typeof(string) && qvalue != null && displayAsUnit != null)
+ {
+ if (displayAsUnit.UnitType != null)
+ {
+ result = qvalue.ToUnit(displayAsUnit.UnitType).ToString(displayAsUnit.Format, culture);
+ }
+ else
+ {
+ result = qvalue.ToString(displayAsUnit.Format, culture);
+ }
+ }
+ else
+ {
+ result = base.ConvertTo(context, culture, value, destinationType);
+ }
+
+ return result;
+ }
+ }
+}