Recipe3.3.Converting a String Representation of an Object into an Actual Object


Recipe 3.3. Converting a String Representation of an Object into an Actual Object

Problem

You need a way of accepting a string containing a textual representation of an object and converting it to an object usable by your application. For example, if you were provided with the string representation of a line (x1, y1)(x2, y2), you would want to convert it into a Line structure.

Solution

Implement a Parse method on your Line structure:

 using System; using System.Text; using System.Text.RegularExpressions; public struct Line : IFormattable {    public Line(int startX, int startY, int endX, int endY)    {    x1 = startX;    x2 = endX;    y1 = startY;    y2 = endY; } public int x1; public int y1; public int x2; public int y2; public override bool Equals(object obj) {    bool isEqual = false;    if (obj == null || (this.GetType() != obj.GetType( )))    {       isEqual = false;    }    else    {       Line theLine = (Line)obj;       isEqual = (this.x1 == theLine.x1) &&        (this.y1 == theLine.y1) &&        (this.x2 == theLine.x2) &&        (this.y2 == theLine.y2);    }    return (isEqual);  } public bool Equals(Line lineObj)  {    bool isEqual = (this.x1 == lineObj.x1) &&     (this.y1 == lineObj.y1) &&     (this.x2 == lineObj.x2) &&     (this.y2 == lineObj.y2);     return (isEqual);  } public override int GetHashCode()  {    return ((x1 + x2) ^ (y1 + y2));  } public static Line Parse(string stringLine) {    if (stringLine == null)     {       throw (new ArgumentNullException(                 "stringLine",                 "A null cannot be passed into the Parse method."));    }    // Take this string (x1,y1)(x2,y2) and convert it to a Line object.    int X1 = 0;    int Y1 = 0;    int X2 = 0;    int Y2 = 0;    MatchCollection MC = Regex.Matches(stringLine,        @"\s*\(\s*(?<x1>\d+)\s*\,\s*(?<y1>\d+)\s*\)\s*\(\s*(?<x2>" +        @"\d+)\s*\,\s*(?<y2>\d+)\s*\)" );    if (MC.Count == 1)    {       Match M = MC[0];       X1 = int.Parse(M.Groups["x1"].Value);       Y1 = int.Parse(M.Groups["y1"].Value);       X2 = int.Parse(M.Groups["x2"].Value);       Y2 = int.Parse(M.Groups["y2"].Value);    }    else    {       throw (new ArgumentException("The value " + stringLine +                                    " is not a well formed Line value."));     }    return (new Line(X1, Y1, X2, Y2));  } public double GetDirectionInRadians() {    int xSide = x2 - x1;    int ySide = y2 - y1;    if (xSide == 0) // Prevent divide-by-zero.        return (0);    else        return (Math.Atan (ySide / xSide));  } public double GetMagnitude() {    int xSide = x2 - x1;    int ySide = y2 - y1;    return (Math.Sqrt( Math.Sqrt((xSide * xSide) + (ySide * ySide)))); } public override string ToString()  {    return (String.Format("({0},{1}) ({2},{3})", x1, y1, x2, y2));  } public string ToString(string format) {    return (this.ToString(format, null));  } public string ToString(IFormatProvider formatProvider) {    return (this.ToString(null, formatProvider));  } public string ToString(string format, IFormatProvider formatProvider) {    StringBuilder compositeStr = new StringBuilder("");    if ((format != null) && (format.ToUpper().Equals("V")))    {       double direction = this.GetDirectionInRadians();                   double magnitude = this.GetMagnitude();       string retStringD = direction.ToString("G5", formatProvider);        string retStringM = magnitude.ToString("G5", formatProvider);       compositeStr.Append(             "magnitude = ").Append(retStringM).Append(                         "\tDirection = ").Append(retStringD);     }    else     {       string retStringX1 = this.x1.ToString(format, formatProvider);        string retStringY1 = this.y1.ToString(format, formatProvider);        string retStringX2 = this.x2.ToString(format, formatProvider);        string retStringY2 = this.y2.ToString(format, formatProvider);       compositeStr.Append("(").Append(retStringX1).Append(",").Append(             retStringY1).Append(")(").                 Append(retStringX2).Append(",").Append(                    retStringY2).Append(")");        }       return (compositeStr.ToString());    } } 

Discussion

The Parse method is used to reconstruct one data typein this case, a Stringinto the data type containing that Parse method. For example, if the string "123" were passed into the int.Parse method, the numeric data type 123 would be extracted and then returned. Many other types in the FCL use a Parse method to reconstruct an object of its own type from another data type, such as a string. Note that you are not limited as far as the type and number of parameters that can be passed into this method. As an example, see how the DateTime.Parse and DateTime.ParseExact methods are defined and overloaded.

The parsing of a string containing the start and end coordinates of a line is a little more difficult. To make things easier, use a regular expression to extract the beginning and ending x and y coordinates.

The regular expression parses out the individual coordinate values provided by the stringLine string parameter. Each found coordinate is passed on to the static int. Parse method on the int structure. This final step obtains the final parsed integer values from the matches produced by the regular expression. If the regular expression does not extract the required coordinates, you can assume that the stringLine parameter does not contain a well-formed string that can be converted to a Line object.

The following code:

 Console.WriteLine("Line.Parse(\"(12,2)(0,45)\") = " + Line.Parse("(12,2)(0,45)"));   Console.WriteLine("Line.Parse(\"(0,0)(0,0)\") = " + Line.Parse("(0,0)(0,0)")); 

produces this output:

 Line.Parse("(12,2)(0,45)") = (12,2) (0,45) Line.Parse("(0,0)(0,0)") = (0,0) (0,0) 

When implementing a Parse method on your own types, you need to consider the situation in which invalid data is passed to this method. When this happens, an ArgumentException should be thrown. When a null is passed in, you should instead throw an ArgumentNullException.


See Also

See the "Parse Method" topic and the parse sample under the ".NET SamplesHow To: Base Data Types" topic in the MSDN documentation.



C# Cookbook
Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More
ISBN: 0596003943
EAN: 2147483647
Year: 2004
Pages: 424

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net