{"id":1931,"date":"2014-05-06T20:52:40","date_gmt":"2014-05-06T20:52:40","guid":{"rendered":"http:\/\/putridparrot.com\/blog\/?p=1931"},"modified":"2014-05-06T20:52:40","modified_gmt":"2014-05-06T20:52:40","slug":"type-conversions-in-c","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/type-conversions-in-c\/","title":{"rendered":"Type conversions in C#"},"content":{"rendered":"<p><strong>Converting one type to another<\/strong><\/p>\n<p>All of the primitive types, such as Int32, Boolean, String etc. implement the IConvertible interface. This means we can easily change one type to another by using<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nfloat f = (float)Convert.ChangeType(&quot;100&quot;, typeof(float));\r\n<\/pre>\n<p>The thing to note regarding the IConvertible type is that it&#8217;s one way, i.e. from your type which implements the IConvertible to another type, but not back (this is where the class TypeConverter, which we&#8217;ll discuss next, comes into play). <\/p>\n<p>So let&#8217;s look at a simple example which converts a Point to a string, and yes before I show the code for implementing IConvertible, we could have simply overridden the ToString method (which I shall also show in the sample code).<\/p>\n<p>First off let&#8217;s create a couple of tests to prove our code works. The first takes a Point and using IConvertible, will generate a string representation of the type. As it uses ToString there&#8217;s no surprise that the second test which uses the ToString method will produce the same output.<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n&#x5B;Fact]\r\npublic void ChangeTypePointToString()\r\n{\r\n   Point p = new Point { X = 100, Y = 200 };\r\n   string s = (string)Convert.ChangeType(p, typeof(string));\r\n\r\n   Assert.Equal(&quot;(100,200)&quot;, s);\r\n}\r\n\r\n&#x5B;Fact]\r\npublic void PointToString()\r\n{\r\n   Point p = new Point { X = 100, Y = 200 };\r\n\r\n   Assert.Equal(&quot;(100,200)&quot;, p.ToString());\r\n}\r\n<\/pre>\n<p>Now let&#8217;s look at our Point type, with an overridden ToString method<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic struct Point : IConvertible\r\n{\r\n   public int X { get; set; }\r\n   public int Y { get; set; }\r\n\r\n   public override string ToString()\r\n   {\r\n      return String.Format(&quot;({0},{1})&quot;, X, Y);\r\n   }\r\n\r\n   \/\/ ... IConvertible methods\r\n}\r\n<\/pre>\n<p>and now let&#8217;s look at a possible implementation of the IConvertible<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nTypeCode IConvertible.GetTypeCode()\r\n{\r\n   throw new InvalidCastException(&quot;The method or operation is not implemented.&quot;);\r\n}\r\n\r\nbool IConvertible.ToBoolean(IFormatProvider provider)\r\n{\r\n   throw new InvalidCastException(&quot;The method or operation is not implemented.&quot;);\r\n}\r\n\r\nbyte IConvertible.ToByte(IFormatProvider provider)\r\n{\r\n   throw new InvalidCastException(&quot;The method or operation is not implemented.&quot;);\r\n}\r\n\r\nchar IConvertible.ToChar(IFormatProvider provider)\r\n{\r\n   throw new InvalidCastException(&quot;The method or operation is not implemented.&quot;);\r\n}\r\n\r\nDateTime IConvertible.ToDateTime(IFormatProvider provider)\r\n{\r\n   throw new InvalidCastException(&quot;The method or operation is not implemented.&quot;);\r\n}\r\n\r\ndecimal IConvertible.ToDecimal(IFormatProvider provider)\r\n{\r\n   throw new InvalidCastException(&quot;The method or operation is not implemented.&quot;);\r\n}\r\n\r\ndouble IConvertible.ToDouble(IFormatProvider provider)\r\n{\r\n   throw new InvalidCastException(&quot;The method or operation is not implemented.&quot;);\r\n}\r\n\r\nshort IConvertible.ToInt16(IFormatProvider provider)\r\n{\r\n   throw new InvalidCastException(&quot;The method or operation is not implemented.&quot;);\r\n}\r\n\r\nint IConvertible.ToInt32(IFormatProvider provider)\r\n{\r\n   throw new InvalidCastException(&quot;The method or operation is not implemented.&quot;);\r\n}\r\n\r\nlong IConvertible.ToInt64(IFormatProvider provider)\r\n{\r\n   throw new InvalidCastException(&quot;The method or operation is not implemented.&quot;);\r\n}\r\n\r\nsbyte IConvertible.ToSByte(IFormatProvider provider)\r\n{\r\n   throw new InvalidCastException(&quot;The method or operation is not implemented.&quot;);\r\n}\r\n\r\nfloat IConvertible.ToSingle(IFormatProvider provider)\r\n{\r\n   throw new InvalidCastException(&quot;The method or operation is not implemented.&quot;);\r\n}\r\n\r\nstring IConvertible.ToString(IFormatProvider provider)\r\n{\r\n   return ToString();\r\n}\r\n\r\nobject IConvertible.ToType(Type conversionType, IFormatProvider provider)\r\n{\r\n   if(conversionType == typeof(string))\r\n      return ToString();\r\n\r\n   throw new InvalidCastException(&quot;The method or operation is not implemented.&quot;);\r\n}\r\n\r\nushort IConvertible.ToUInt16(IFormatProvider provider)\r\n{\r\n   throw new InvalidCastException(&quot;The method or operation is not implemented.&quot;);\r\n}\r\n\r\nuint IConvertible.ToUInt32(IFormatProvider provider)\r\n{\r\n   throw new InvalidCastException(&quot;The method or operation is not implemented.&quot;);\r\n}\r\n\r\nulong IConvertible.ToUInt64(IFormatProvider provider)\r\n{\r\n   throw new InvalidCastException(&quot;The method or operation is not implemented.&quot;);\r\n}\r\n<\/pre>\n<p><strong>TypeConverters<\/strong><\/p>\n<p>As mentioned previously, the IConvertible allows us to convert a type to one of the primitive types, but what if we want more complex capabilities, converting to and from various types. This is where the TypeConverter class comes in. <\/p>\n<p>Here we develop our type as normal and then we adorn it with the TypeConverterAttribute at the struct\/class level. The attribute takes a type derived from the TypeConverter class. This TypeConverter derived class does the actual type conversion to and from our adorned type.<\/p>\n<p>Let&#8217;s again create a Point struct to demonstrate this on<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n&#x5B;TypeConverter(typeof(PointTypeConverter))]\r\npublic struct Point\r\n{\r\n   public int X { get; set; }\r\n   public int Y { get; set; }\r\n}\r\n<\/pre>\n<p><em>Note: We can also declare the TypeConverter type using a string in the standard Type, Assembly format, i.e. [TypeConverter(&#8220;MyTypeConverters.PointTypeConverter, MyTypeConverters)]<br \/>\nif we wanted to reference the type in an external assembly.<\/em><\/p>\n<p>Before we create the TypeConverter code, let&#8217;s take a look at some tests which hopefully demonstrate how we use the TypeConverter and what we expect from our conversion code.<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n&#x5B;Fact]\r\npublic void CanConvertPointToString()\r\n{\r\n   TypeConverter tc = TypeDescriptor.GetConverter(typeof(Point));\r\n\r\n   Assert.True(tc.CanConvertTo(typeof(string)));\r\n}\r\n\r\n&#x5B;Fact]\r\npublic void ConvertPointToString()\r\n{\r\n   Point p = new Point { X = 100, Y = 200 };\r\n\r\n   TypeConverter tc = TypeDescriptor.GetConverter(typeof(Point));\r\n\r\n   Assert.Equal(&quot;(100,200)&quot;, tc.ConvertTo(p, typeof(string)));\r\n}\r\n\r\n&#x5B;Fact]\r\npublic void CanConvertStringToPoint()\r\n{\r\n   TypeConverter tc = TypeDescriptor.GetConverter(typeof(Point));\r\n\r\n   Assert.True(tc.CanConvertFrom(typeof(string)));\r\n}\r\n\r\n&#x5B;Fact]\r\npublic void ConvertStringToPoint()\r\n{\r\n   TypeConverter tc = TypeDescriptor.GetConverter(typeof(Point));\r\n\r\n   Point p = (Point)tc.ConvertFrom(&quot;(100,200)&quot;);\r\n   Assert.Equal(100, p.X);\r\n   Assert.Equal(200, p.Y);\r\n}\r\n<\/pre>\n<p>So as you can see, to get the TypeConverter for our class we call the static method GetConverter on the TypeDescriptor class. This returns an instance of our TypeConverter (in this case our PointTypeConverter). From this we can check whether the type converter can convert to on from a type and then using the ConvertTo or ConvertFrom methods on the TypeConverter we can convert the type.<\/p>\n<p>The tests above show that we expect to be able to convert a Point to a string where the string takes the format &#8220;(X,Y)&#8221;. So let&#8217;s look at an implementation for this <\/p>\n<p><em>Note: note, this is an example of how we might implement this code and does not have full error handling, but hopefully gives a basic idea of what you might implement.<\/em><\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic class PointTypeConverter : TypeConverter\r\n{\r\n   public override bool CanConvertTo(ITypeDescriptorContext context, \r\n            Type destinationType)\r\n   {\r\n      return (destinationType == typeof(string)) || \r\n         base.CanConvertTo(context, destinationType);\r\n   }\r\n\r\n   public override object ConvertTo(ITypeDescriptorContext context, \r\n            CultureInfo culture, \r\n            object value, \r\n            Type destinationType)\r\n   {\r\n      if (destinationType == typeof(string))\r\n      {\r\n         Point pt = (Point)value;\r\n         return String.Format(&quot;({0},{1})&quot;, pt.X, pt.Y);\r\n       }\r\n       return base.ConvertTo(context, culture, value, destinationType);\r\n   }\r\n\r\n   public override bool CanConvertFrom(ITypeDescriptorContext context, \r\n            Type sourceType)\r\n   {\r\n      return (sourceType == typeof(string)) ||\r\n         base.CanConvertFrom(context, sourceType);\r\n   }\r\n\r\n   public override object ConvertFrom(ITypeDescriptorContext context, \r\n            CultureInfo culture, \r\n            object value)\r\n   {\r\n      string s = value as string;\r\n      if (s != null)\r\n      {\r\n         s = s.Trim();\r\n\r\n         if(s.StartsWith(&quot;(&quot;) &amp;&amp; s.EndsWith(&quot;)&quot;))\r\n         {\r\n            s = s.Substring(1, s.Length - 2);\r\n\r\n            string&#x5B;] parts = s.Split(',');\r\n            if (parts != null &amp;&amp; parts.Length == 2)\r\n            {\r\n               Point pt = new Point();\r\n               pt.X = Convert.ToInt32(parts&#x5B;0]);\r\n               pt.Y = Convert.ToInt32(parts&#x5B;1]);\r\n               return pt;\r\n            }\r\n         }\r\n      }\r\n      return base.ConvertFrom(context, culture, value);\r\n   }\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Converting one type to another All of the primitive types, such as Int32, Boolean, String etc. implement the IConvertible interface. This means we can easily change one type to another by using float f = (float)Convert.ChangeType(&quot;100&quot;, typeof(float)); The thing to note regarding the IConvertible type is that it&#8217;s one way, i.e. from your type which [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[3],"tags":[],"class_list":["post-1931","post","type-post","status-publish","format-standard","hentry","category-c"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/1931","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=1931"}],"version-history":[{"count":17,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/1931\/revisions"}],"predecessor-version":[{"id":1948,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/1931\/revisions\/1948"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=1931"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=1931"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=1931"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}