none
(Int32) or Int32.Parse

    Question

  • Hello,

    I have the following:
    _roles.Root.Elements("Role").ToDictionary(r => (Int32)r.Element("Id"), // ...
    _roles is an XDocument.

    Should I use (Int32)r.Element("Id") or Int32.Parse(r.Element("Id"))?

    Or even Int32.Parse(r.Element("Id").Value)?    Note: I added the value

    What I have is working but I am not sure of the correct way to do this ...

    Thanks,
    Miguel

    Monday, March 01, 2010 2:21 AM

Answers

  • Tostring() without parameters and Parse(string) are not culture invariant. They use the current culture.
    To use InvariantCulture, you need to use

    ToString(CultureInfo.InvariantCulture)

    and

    Parse(s, CultureInfo.InvariantCulture)

    Or you can simply use

    XElement product = new XElement("Message",
       new XElement("Id", id),
       new XElement("Description", product.Description),
       new XElement("Active", product.Active)
    );
    Monday, March 01, 2010 3:06 PM
  • Hi Miguel,

    You have basically four options:
    1. Direct cast: (Int32)value
    2. Parse: Int32.Parse
    3. TryParse: Int32.TryParse
    4. Convert: Convert.ToInt32

    Depends on what you have in the "Id" field. if this field might not be a valid representative of an integer (e.g. "567*$"), all options above throw exception except number 3. This will help improving the performance since you do not need to catch the exception or check for validity befor casting. The convert is a wrapper around the Parse method.

    some related links:
    http://dotnetperls.com/int-parse-conversion
    http://fatagnus.com/why-you-should-use-tryparse-in-c/
    http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/9b84d364-d868-44e4-a624-a2577923988d/

    Hope this helps
    Hamed
    Monday, March 01, 2010 3:38 AM
  • You don't "need" to perform the conversion as Louis.fr demonstrated, but personally I prefer to have the compile-time type checking of explicitly using XmlConvert. E.g.

    // duration is of type System.Windows.Duration, created from a TimeSpan value.
    
    // Results in FormatException.
    XElement element1 = new XElement("Interval", duration);
    TimeSpan value1 = XmlConvert.ToTimeSpan(element1.Value);
    
    // Won't compile.
    XElement element2 = new XElement("Interval", XmlConvert.ToString(duration));
    TimeSpan value2 = XmlConvert.ToTimeSpan(element2.Value);
    
    // Fine.
    XElement element3 = new XElement("Interval", XmlConvert.ToString(duration.TimeSpan));
    TimeSpan value3 = XmlConvert.ToTimeSpan(element3.Value);

    Now you can argue that your tests should pick this up or that you're only (currently) dealing with a small set of types, but in my experience having the compiler detect bugs is the ideal. Another thing to note with the XElement constructor is that value types will need to be boxed and unboxed. This may not result in any noticeable performance problems but it's still unnecessary IMO and easily avoided.
    Monday, March 01, 2010 4:18 PM

All replies

  • Hi Miguel,

    You have basically four options:
    1. Direct cast: (Int32)value
    2. Parse: Int32.Parse
    3. TryParse: Int32.TryParse
    4. Convert: Convert.ToInt32

    Depends on what you have in the "Id" field. if this field might not be a valid representative of an integer (e.g. "567*$"), all options above throw exception except number 3. This will help improving the performance since you do not need to catch the exception or check for validity befor casting. The convert is a wrapper around the Parse method.

    some related links:
    http://dotnetperls.com/int-parse-conversion
    http://fatagnus.com/why-you-should-use-tryparse-in-c/
    http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/9b84d364-d868-44e4-a624-a2577923988d/

    Hope this helps
    Hamed
    Monday, March 01, 2010 3:38 AM
  • In addition to Hamed advice...
    We can compare these methods in three condition:
    1. Impossible Condition.
    2. Possible Condotion.
    3. Null Condition.
    Let's make it more clear by an example
    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace StringConvertingWaysToInt32
    {
        class Program
        {
            static void Main(string[] args)
            {
                object o;
    
                Console.WriteLine("Impossible Condition");
                o = "1$";
                TryParse(o);
                Parse(o);
                DirectCast(o);
                Convert(o);
                Console.WriteLine("====================");
    
                Console.WriteLine("Possible Condition");
                o = "1";
                TryParse(o);
                Parse(o);
                DirectCast(o);
                Convert(o);
                Console.WriteLine("====================");
    
                Console.WriteLine("Null Condition");
                o = null;
                TryParse(o);
                Parse(o);
                DirectCast(o);
                Convert(o);
                Console.WriteLine("====================");
    
                Console.WriteLine("Press any key to exit...");
                Console.ReadKey();
            }
            static void TryParse(object o)
            {
                Console.Write("Try parse Result For '{0}': ", o);
                try
                {
                    int i;
                    Console.WriteLine(Int32.TryParse(o.ToString(), out i));
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
            static void Parse(object o)
            {
                Console.Write("Parse Result For '{0}': ", o);
                try
                {
                    Console.WriteLine(Int32.Parse(o.ToString()));
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
            static void DirectCast(object o)
            {
                Console.Write("Direct Cast Result For '{0}': ", o);
                try
                {
                    Console.WriteLine((int)o);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
            static void Convert(object o)
            {
                Console.Write("Convert Result For '{0}': ", o);
                try
                {
                    Console.WriteLine(System.Convert.ToInt32(o));
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
        }
    }
    
    //output
    /*
    Impossible Condition
    Try parse Result For '1$': False
    Parse Result For '1$': Input string was not in a correct format.
    Direct Cast Result For '1$': Specified cast is not valid.
    Convert Result For '1$': Input string was not in a correct format.
    ====================
    Possible Condition
    Try parse Result For '1': True
    Parse Result For '1': 1
    Direct Cast Result For '1': Specified cast is not valid.
    Convert Result For '1': 1
    ====================
    Null Condition
    Try parse Result For '': Object reference not set to an instance of an object.
    Parse Result For '': Object reference not set to an instance of an object.
    Direct Cast Result For '': Object reference not set to an instance of an object.
    
    Convert Result For '': 0
    ====================
    Press any key to exit...
    */

    My Blog - MSDN Complement by providing Visual C# Walkthroughs and Sample Codes - Founded In February 24, 2010
    Monday, March 01, 2010 6:25 AM
  • It's impossible to say what is the "correct way" as you haven't provided enough information about the format of the Id element. In XML you typically have the lexical space (the textual representation) and the value space (the semantic representation). If your definition for the Id element conforms to some established standard, such as the int type in XML Schema, then only the first method (the cast) is correct. All of the other methods could potentially fail as they use the current thread's culture for formatting information, which could have different settings to what you expect, such as the positive and negative symbols not being + and -. You could use the overrides that accept an IFormatProvider but I'd recommend that you use XML Schema definitions in your XML and the XmlConvert class to perform all of your conversions. The reason the cast works is because XElement overloads the explicit conversion operator but it ultimately delegates to XmlConvert. It's up to you whether you want to continue using the cast syntax or whether you want to explicitly call XmlConvert. Personally I'd choose the latter as it makes the intent of the code easier to follow.
    Monday, March 01, 2010 12:47 PM
  • Hello,

    In my XML file the ID will always be a correct number like 1, 2, 3, ... 1020, etc.
    I know that because it is generated from code and not from any user input.
    And it is not different from culture to culture. Is always the same. An int that serves as a identifier like an SQL Server Int for Id.

    So what you are saying is that in this case I should use (Int32) .... Correct?

    Thanks,
    Miguel
    Monday, March 01, 2010 1:10 PM
  • Yes, use either the cast or XmlConvert. Note that generating the Id from code is no guarantee that it is culture-insensitive. The code must be authored to perform invariant conversions. Some languages/platforms make this easier than others.
    Monday, March 01, 2010 2:07 PM
  • Let me give a better idea. This is how I create an XElement:
          XElement product = new XElement("Message",
            new XElement("Id", id.ToString()),
            new XElement("Description", product.Description),
            new XElement("Active", product.Active.ToString())
          );


    And this is how I read it:
    Product product =  _products.Root.Elements("Product").Select(p => new Product {
      Id = XmlConvert.ToInt32(m.Element("Id").Value),
      Description = m.Element("Content").Value,
      Active = Boolean.Parse(r.Element("Active").Value)
    }).FirstOrDefault(p => p.Id == id);
    My product model is something like:
    public class Product {
      public Int32 Id { get; set; }
      public String Description { get; set; }
      public Boolean Active { get; set; }
    }
    1. When creating a new XElement I use ToString() to convert any type, other then string, like DateTime, Boolean, Int, etc
        Unlesse I need to save a Base64String so I use Convert.ToBase64String();

    2. When getting the data from the XElement to the model I am using Int32.Parse, Boolean.Parse, DateTime.Parse, etc.
        Unless when getting a Base64String where I use Convert.FromBase64String(),

    I want all the data in the XML file to be culture invariant. If I need some change I prefer to do something later on the model. Does this make sense?

    So what is the proper way to do this?
    1. Can I still use ToString() when creating a XMLElement from my model?
        And Convert.ToBase64String when using Base64String?

    2. Use XmlConvert instead of parse ... Correct?
        I was checking XMLConvert and I have a lot of options: ToInt32, ToBoolean, ToDateTime, etc
        So I should use XMLConvert for these cases, nothing when the original data is String and Convert.FromBase64String when is a Base64String.
        Is this correct?

    Sorry for so many questions. I am just trying to make this correctly.
    I am saving and getting some data from a few small XML files and I would like to make sure I am doing the data conversion correctly.

    Thank You,
    Miguel




    Monday, March 01, 2010 2:44 PM
  • Tostring() without parameters and Parse(string) are not culture invariant. They use the current culture.
    To use InvariantCulture, you need to use

    ToString(CultureInfo.InvariantCulture)

    and

    Parse(s, CultureInfo.InvariantCulture)

    Or you can simply use

    XElement product = new XElement("Message",
       new XElement("Id", id),
       new XElement("Description", product.Description),
       new XElement("Active", product.Active)
    );
    Monday, March 01, 2010 3:06 PM
  • Or you can simply use

    XElement product = new XElement("Message",
       new XElement("Id", id),
       new XElement("Description", product.Description),
       new XElement("Active", product.Active)
    );
    You mean I don't need any conversion when creating the XElement? And it is culture invariant?

    I suppose in that case I would only need if I would like to save a String as Base64String ...

    So basically, you saying to not use any conversion when creating the XElement and use XMLConvert when reading it. Correct?

    What about a Guid? To save a Guid on the XMLElement? Do I not need to convert it to string firs?

    Sorry, no I am confused.

    Thanks,
    Mguel


    Monday, March 01, 2010 3:20 PM
  • Try it:

    XElement tryMe = new XElement("TryMe",
        new XElement("Date", DateTime.Now),
        new XElement("Int", 1234),
        new XElement("Float", 3.1416),
        new XElement("Guid", new Guid(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)),
        new XElement("Boolean", true)
        );
    Console.WriteLine(tryMe);
    
    Monday, March 01, 2010 3:26 PM
  • You don't "need" to perform the conversion as Louis.fr demonstrated, but personally I prefer to have the compile-time type checking of explicitly using XmlConvert. E.g.

    // duration is of type System.Windows.Duration, created from a TimeSpan value.
    
    // Results in FormatException.
    XElement element1 = new XElement("Interval", duration);
    TimeSpan value1 = XmlConvert.ToTimeSpan(element1.Value);
    
    // Won't compile.
    XElement element2 = new XElement("Interval", XmlConvert.ToString(duration));
    TimeSpan value2 = XmlConvert.ToTimeSpan(element2.Value);
    
    // Fine.
    XElement element3 = new XElement("Interval", XmlConvert.ToString(duration.TimeSpan));
    TimeSpan value3 = XmlConvert.ToTimeSpan(element3.Value);

    Now you can argue that your tests should pick this up or that you're only (currently) dealing with a small set of types, but in my experience having the compiler detect bugs is the ideal. Another thing to note with the XElement constructor is that value types will need to be boxed and unboxed. This may not result in any noticeable performance problems but it's still unnecessary IMO and easily avoided.
    Monday, March 01, 2010 4:18 PM