6

I'm using reflection to create some objects. The values I'm setting are read in from a file so they're natively in a string format and I need to convert them to the datatype of the property.

My question is, which is faster/better to use: the Convert.ToX(...) methods or the X.Parse(...) methods?

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Micah
  • 111,873
  • 86
  • 233
  • 325
  • 1
    I can't tell you, but I can tell you how to find out... Open up ILDasm and open up the dll with all the classes in (takes a bit of finding) you can then see the IL code they use. It's not really readable, but you can see what it's calling and check if which on calls which. – Matt May 12 '11 at 14:24
  • 2
    Or just use ILSpy to see C# code instead of IL instructions... – Daniel Hilgarth May 12 '11 at 14:25
  • 1
    possible duplicate of [The difference between convert and parse.](http://stackoverflow.com/questions/3486810/the-difference-between-convert-and-parse) – H H May 12 '11 at 15:28

5 Answers5

11

All of the Convert.ToX functions that accept an argument of type string ultimately call down to the Parse method of the appropriate datatype anyway.

For example, Convert.ToInt32(string) looks something like this:

public static int ToInt32(string value)
{
   if (value == null)
   {
      return 0;
   }
   return int.Parse(value, CultureInfo.CurrentCulture);
}

The same thing for all of the other numeric conversion methods, including Decimal and DateTime. So it's fairly irrelevant which one you use; the result (and speed) will be the same in either case.

Really, the only difference is the if (value == null) guard clause at the beginning. Whether or not that's convenient depends on the specific use case. Generally, if you know that you have a non-null string object, you might as well use Parse. If you're not sure, ConvertToX is a safer bet, requring less null-checking code inline.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • Good sleuthing @Cody! I'll opt to use the Convert methods since I don't have to worry checking for null. – Micah May 12 '11 at 14:32
  • A variable being null when I don't expect it to is usually a bug. So I want to get an exception instead of a silent data corruption. So I'd say you have to worry more about null checks when using Convert than when using parse. – CodesInChaos May 12 '11 at 14:34
  • @Code: Yeah, I agree. But there are cases where you don't *have* an particular expectation. It would be perfectly reasonable for the variable to both be or not be null. In that case, there's nothing wrong with `Convert`. – Cody Gray - on strike May 12 '11 at 14:36
  • I still like stating which default value I want explicitly. – CodesInChaos May 12 '11 at 14:41
  • This doesn't seem very object-oriented to me. Your classes should either have a static `Parse` method that returns an instance of the class, or have constructors that take other types as arguments. Using a utility class smells faintly of encapsulation violation to me (since you're putting a dependency in the `Convert` class that your class will always support conversion from other specified types). – TMN May 15 '11 at 20:52
  • @TMN: It depends on your definition of object-oriented. It's *extremely* polymorphic. But yes, it is separated into a utility class, rather than being exposed as a method on each type. Each type *does* have a static `Parse` method that you can choose to use if you prefer. I mentioned that in my answer. The advantage of the `Convert` class is the null checking and the polymorphism. The point here is that the difference is so minimal as to imply your choice should be based on some standard other than performance. – Cody Gray - on strike May 16 '11 at 05:03
1

They are exactly the same! The Convert.ToX(String) methods actually call the X.Parse(String) methods.

Cory Nelson
  • 29,236
  • 5
  • 72
  • 110
1

According to what i see in Reflector , Convert form string is a wrapper around Parse. so it stand to reason using parse is marginally better in performance.

EDIT: after Cody pointed out that optimization will make the difference almost nothing, i tested on my machine, and indeed the execution times for Parse and Convert came out the same when parsing 1 million inetgers in a loop.

EDIT2: here you go yas4891 ,its actually the code you used with very minor changes.

public static void Main()
        {
            int tRuns = 1000000;
            List<String> tList = new List<string>();
            for (int i = 0; i < tRuns; i++) tList.Add(i.ToString());
            Stopwatch s = new Stopwatch();
            s.Start();
            int tSum = 0;
            for (int i = tRuns - 1; i >= 0; i--) 
            {
                tSum += Convert.ToInt32(tList[i]);
            }
            s.Stop();
            Console.WriteLine("convert: " + s.ElapsedMilliseconds);

            Console.WriteLine("tSum:" + tSum); 

            s.Reset();
            s.Start();
            tSum = 0; 
            for (int i = tRuns - 1; i >= 0; i--) 
            { 
                tSum += Int32.Parse(tList[i]); 
            } 
            s.Stop();
            Console.WriteLine("parse: " + s.ElapsedMilliseconds);
            Console.WriteLine("tSum:" + tSum);
            Console.ReadKey();
        }
Menahem
  • 3,974
  • 1
  • 28
  • 43
  • The first part is more or less correct. But why does your conclusion "stand to reason"? That indicates to me that they're the same thing, not that one is "better", even marginally so. – Cody Gray - on strike May 12 '11 at 14:34
  • @Cody Gray you are correct i was not clear here, updated the answer – Menahem May 12 '11 at 14:36
  • That's not really correct, either. I assumed that's where you were going, but once the JIT compiler gets through with the code, it's highly unlikely that there'll be *any* perceptible performance difference between the two methods. – Cody Gray - on strike May 12 '11 at 14:37
  • since there`s the null check and extra function call, there must be a difference. it`s as you say not perceptible, but its there, and in a tight loop might even amount to something. thats why i said marginal. does this make sense? – Menahem May 12 '11 at 14:41
  • 1
    You're doing that thing programmers do where they *assume* things instead of testing them, or better yet, just resisting the temptation to prematurely optimize things. The entire method qualifies for inlining, it's extremely unlikely that even a million iterations will show a noticeable performance difference based on a single `if` statement. – Cody Gray - on strike May 12 '11 at 14:42
  • @Cody Gray well, i am a progammer. but lucky enough theres some proof of my theory in a new answer juts posted. take a look. – Menahem May 12 '11 at 14:45
  • Beat you to it. Check my comment to that answer. It's cheating to profile with optimizations disabled. That means the JIT compiler doesn't get to do its thing, and nothing gets inlined. – Cody Gray - on strike May 12 '11 at 14:46
  • good point, ill stick around and see what happens if i turn the optimization on with his source code. (thanks for the free lessons by the way) – Menahem May 12 '11 at 14:49
  • @Cody Gray after running a test i get identical execution times for `Convert` and `Parse` parsing 1 million integers. updating my answer. – Menahem May 12 '11 at 15:08
  • @Menahem: could you please provide the source? – yas4891 May 12 '11 at 15:38
  • @yas4891 , sure see my update. i used your code with minor changes. – Menahem May 15 '11 at 06:01
1

Another possibility is the TryParse methods. These are particularly useful if there is a possibility that the value cannot be parsed successfully. Instead of throwing an exception the call will return a bool indicating whether the operation was successful. This executes much faster and is a cleaner implementation as compared to dealing with the exception.

Brian Gideon
  • 47,849
  • 13
  • 107
  • 150
-1

using the following code

int tRuns = 1000000;
List<String> tList = new List<string>();

for (int i = 0; i < tRuns; i++)
   tList.Add(i.ToString());


PerformanceMeter.Start();
int tSum = 0;
for (int i = tRuns-1; i >= 0; i--)
{
   tSum += Convert.ToInt32(tList[i]);
}

PerformanceMeter.LogAndStop("using Convert.ToInt32:");

cLogger.Info("tSum:" + tSum);
PerformanceMeter.Start();

tSum = 0;
for (int i = tRuns-1; i >= 0; i--)
{
   tSum += Int32.Parse(tList[i]);
}

PerformanceMeter.LogAndStop("using Int32.Parse:");
cLogger.Info("tSum:" + tSum);

gives me the following output:

{ PerformanceMeter}:178 INFO: - using Convert.ToInt32:: 233,0133 ms
{ Program}: 92 INFO: - tSum:1783293664
{ PerformanceMeter}:178 INFO: - using Int32.Parse:: 179,0103 ms
{ Program}:102 INFO: - tSum:1783293664

So at least for Int32 it seems to be more efficient to use Int32.Parse. However this may be different in your scenario and I suppose you should do a similiar test.

yas4891
  • 4,774
  • 3
  • 34
  • 55
  • Erm, you didn't seriously try to test the performance of something when compiled in "Debug" mode **with optimizations disabled**, did you? That's a **completely meaningless** test. Good thing I'm out of votes for the day, this is an easy -1. – Cody Gray - on strike May 12 '11 at 14:44
  • @Cody: Just because I used debug outputs for this quick example ? Just so you understand: I did this quick test in one of my programs that is set to 'Release' and I use log4net DEBUG outputs even in my releases – yas4891 May 12 '11 at 14:53
  • Yes. The bold parts of my comment are important. Debug mode disables all code optimizations, including but not limited to the JIT compiler. The result is meaningless data that lines up with your intuitions, but doesn't hold up once optimizations are applied. Doing performance tests with debug code shows a fundamental misunderstanding of the purposes for each. – Cody Gray - on strike May 12 '11 at 14:55
  • I know that the bold parts are important. I know that testing without optimization is meaningless. However you confuse log4net DEBUG with actual compilation – yas4891 May 12 '11 at 14:58
  • Maybe. I have no idea what that is. I do know, however, that if you don't compile the code with optimizations enabled and execute it *without* attaching the debugger, you're just wasting your time when trying to profile. – Cody Gray - on strike May 12 '11 at 15:00
  • I agree on the fact that the output 'DEBUG' might cause confusion and for sake of clarity I will remove that. Nonetheless: The results are valid (on my machine ;-) – yas4891 May 12 '11 at 15:04
  • 1
    Looping over 100 million (yes, 100 million) times, I can't get more than 5 milliseconds difference between the two methods. Compiled with optimizations enabled, running outside of VS without the debugger attached. Talk about insignificant. I'm still suspicious of your perf tests. – Cody Gray - on strike May 12 '11 at 15:13
  • @Cody: could you provide the source? I'm curious to learn / see why there's such a big difference on my machine. In the mean time I'll transfer the executable etc. to a VM without VS installed – yas4891 May 12 '11 at 15:22
  • I didn't save the source. But it looked extremely similar to the code you have above. I created a `List` and stored all the numbers in it. Then I set up two loops to iterate through each item in the list, use a type conversion method to convert the value to an integer, and add it to a `sum` variable (just to prevent the JITer from optimizing anything out altogether). The only thing different is that I used the `System.Diagnostics.Stopwatch` class for timing. The important thing is that I compiled in Release mode, closed VS, and ran the application (it was a Console app). – Cody Gray - on strike May 12 '11 at 15:43
  • that's crazy. The same thing I did. I did the same thing again on my VM. Same difference there. Would you mind to have a look at it via Teamviewer later on? – yas4891 May 12 '11 at 16:20
  • I don't know what Teamviewer is. But if you're still testing it though log4net (which I don't have any experience with) that's very likely affecting the results. I used a new, empty Console application project. No extra fluff along for the ride. – Cody Gray - on strike May 13 '11 at 02:47
  • nope. I have replaced it with Console.WriteLine() and am using a new console application. – yas4891 May 13 '11 at 06:03