开发者

TypeConverter vs. Convert vs. TargetType.Parse

As far as I know, there are at least 3 ways to convert data types in .NET:


using System.ComponentModel.TypeConverter

var conv = System.ComponentModel.TypeDescriptor.GetConverter(typeof(int));
var i1 = (int)conv.ConvertFrom("123");

using System.Convert.ChangeType():

开发者_开发技巧
var i2 = (int) Convert.ChangeType("123", typeof (int));

using the Parse/TryParse methods of the destination type:

var i3 = int.Parse("123"); // or TryParse


Are there any guidelines or rules-of-thumb when to use which method to convert between the .NET base data types (especially from string to some other data type)?


I'm going to post here 6 years late, because I think this is a good question and I am not satisfied with the existing answers.

The static Parse/TryParse methods can be used only when you want to convert from string to the type that has those methods. (use TryParse when you expect that the conversion may fail).

The point of System.Convert is, as its documentation says, to convert from a base data type to another base data type. Note that with Convert you also have methods that take an Object and figure out by themselves how to convert it.

As to System.ComponentModel.TypeConverter, as the "typeconverter" stack overflow tag's documentation, they are used primarily to convert to and from string, when you want to provide a text representation of a class instance for use by designer serialization or for display in property grids


Convert

Convert class uses the IConvertible methods implemented in the target type.

Unfortunately, implementing IConvertible means writing lots of boilerplate code and Convert.ChangeType causes boxing if the target type is a struct.

TypeConverterAttribute

TypeDescriptor.GetConverter uses the TypeConverterAttribute and IMHO offers both a better API to convert a type and a more elegant way to make a type convertible. But it suffers the same performance issues with the Convert class, caused by the methods not being generic.

Parse/TryParse

Using T.Parse/T.TryParse methods is the de facto way of creating an object from a string since it doesn't involve unnecessary boxing. They also usually have overloads that provide greater control of how to parse the string.

TryParse methods allow you to handle cases where the string you want to parse is obtained from user input or another mean that doesn't guarantee a properly formatted string, without throwing exceptions.


So you should call the type's Parse/TryParse methods when you can and fallback to the other ways only when you don't know the target type in the compile time, i.e. when you only have a Type object that represents your target type.

You can also have look at my little library called ValueString that finds the most suitable parsing method of a type and uses it to parse the string.


According to my personal preference and coding standards I choose between the following:

  1. Convert. I use this when I am absolutely sure that the values will be what I expect.

    int i = Convert.ToInt32("123");
    
  2. TryParse. I use this when I am handling user input. This also has the benefit to be able to use localized formatting when parsing.

    int i = 0;
    bool parsed = Int32.TryParse("123", out i);
    

There is also the possibility to use TryParseExact, where a certain pattern can be parsed. It can be useful in certain cases.


Just found out a case that TypeConvert.ConvertFrom(object) throws exception. If you want to convert an Integer 0/1 to a Boolean. You will get exception using TypeConvert.ConvertFrom(1) or (0). In this case, Convert.ChangeType(1, System.Boolean) works.


As a general rule of thumb, you should be avoiding the Convert class altogether. There are reasons to use it (e.g, you do not know the source type), but if you already know your source type is a string then Parse (or, more correctly, TryParse) is always the right method to use.

As for type converters, they are more often than not used when a framework (such as WPF) uses reflection to determine the right sort of type converter.

You forgot another way of converting, that is the direct cast. Take this code for example

object i = 1;
int myInt = (int)i;

This is a bit of a contrived example, but I already know that i is an int, its just that its boxed into an object. In this case I do not need to convert i, I just need to directly cast it to the type which I know it already is.


I pretty much always use the int/double/etc.Parse() methods, when I'm certain it's a number. In any case of doubt, I us the .TryParse() methods, as an all-in-one solution including parsing and checking. I have this feeling that checking and parsing combined is slightly more performant than doing them separately.

TypeConverter is probably only useful when you don't really know the types at compile time.


Another late answer. I have an application where I was using some code that looks like this:

var finalValue = Convert.ChangeType(sourceValue, targetProperty.PropertyType);

sourceValue would be a string representation of what I wanted which normally would be a primitive under a wrapper class. This way would work with regular data types. Even with entire classes. However, one day I stupidly decided to change the datatype of a property that was a double to a nullable one double? guess what? boom!

invalid cast from string to nullable double

This is the perfect scenario where you should use the TypeConverter class as follows:

void Main()
{
    var ss = new[] {"2.01", "3.99", ""};
    var conv = TypeDescriptor.GetConverter(typeof(A).GetProperties().First().PropertyType);
    Console.WriteLine(string.Join(",", ss.Select(s => conv.ConvertFrom(s))));
}

class A {
    public double? b {get; set;}
}

//2.01,3.99,
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜