TypeConverter vs. Convert vs. TargetType.Parse
Posted
技术标签:
【中文标题】TypeConverter vs. Convert vs. TargetType.Parse【英文标题】: 【发布时间】:2011-10-24 01:13:40 【问题描述】:据我所知,在.NET中转换数据类型至少有3种方式:
使用System.ComponentModel.TypeConverter
var conv = System.ComponentModel.TypeDescriptor.GetConverter(typeof(int));
var i1 = (int)conv.ConvertFrom("123");
使用System.Convert.ChangeType():
var i2 = (int) Convert.ChangeType("123", typeof (int));
使用目标类型的Parse/TryParse 方法:
var i3 = int.Parse("123"); // or TryParse
是否有任何指南或经验法则何时使用哪种方法在 .NET 基本数据类型之间进行转换(尤其是从字符串到其他数据类型)?
【问题讨论】:
哦,别忘了System.ComponentModel.NullableConverter
。 System.Convert
无法处理可空类型(将 string "123"
转换为 int?
类型),而不是将其构建到现有转换器中,他们只是制作了另一个 :)
Convert.ChangeType 使用 int.Parse() 所以没有区别。 TypeConverter 使用反射,如果你关心性能,最好避免。
@Hans:为什么不将其发布为答案?似乎是一条有价值的信息。
【参考方案1】:
作为一般经验法则,您应该完全避免使用 Convert
类。使用它是有原因的(例如,您不知道源类型),但如果您已经知道您的源类型是 string
,那么 Parse
(或者更准确地说,TryParse
)总是正确的方法使用。
对于类型转换器,当框架(例如 WPF)使用反射来确定正确类型的类型转换器时,通常会使用它们。
你忘记了另一种转换方式,那就是直接施法。以这段代码为例
object i = 1;
int myInt = (int)i;
这是一个人为的例子,但我已经知道 i
是一个 int,只是它被装箱成一个 object
。在这种情况下,我不需要转换i
,只需将其直接转换为我知道的类型即可。
【讨论】:
只有当对象实际上已经是那种类型时才可以进行直接转换?就像在您的示例中一样,但是将字符串转换为数字根本不起作用。 @Joachim - 当然,我添加它是为了后代,因为它通常与转换混淆。 @Jamiec,您能否提供您的 stmt 背后的推理“作为一般经验法则,您应该避免使用 Convert 类”?我希望看到一些推理、博客文章等来为该声明辩护。谢谢。 我已经完成了研究,没有发现任何会引发危险信号的东西(这就是为什么我询问您强烈反对它的原因)。性能在微秒内足够接近,不会产生任何影响(通过使用 Vance Morrison 的 MeasureIt 应用程序 - 前 CLR 性能架构师)。如果课程在那里并且没有合理的理由不使用它,那么我会说这样做。我完全赞成了解框架和运行时的作用。但是,在这种情况下,查看 Convert.ChangeType() 只不过是一个学术练习 (续)有一个框架可以为您做事并抽象出实现细节。与流行的看法相反,在 .NET 4.5 中使用类型系统的速度非常快,因为反射引擎基本上是重新编写的。我已经围绕它进行了大量的性能测试,它比以前版本的框架快几个数量级。所以,我会问“一刀切”的解决方案有什么问题,如果它 1. 性能一样好 2. 更易于维护,而不是在您的应用程序中分布多种类型转换方式?【参考方案2】:当我确定它是一个数字时,我几乎总是使用 int/double/etc.Parse() 方法。如有任何疑问,我使用 .TryParse() 方法,作为包括解析和检查在内的一体化解决方案。我有这样的感觉,检查和解析结合起来比单独做稍微好一点。
TypeConverter 可能仅在您在编译时并不真正了解类型时才有用。
【讨论】:
【参考方案3】:根据我的个人喜好和编码标准,我会在以下选项中进行选择:
Convert
。当我完全确定这些值符合我的预期时,我会使用它。
int i = Convert.ToInt32("123");
TryParse
。我在处理用户输入时使用它。这也有利于在解析时使用本地化格式。
int i = 0;
bool parsed = Int32.TryParse("123", out i);
还可以使用 TryParseExact,其中可以解析特定模式。在某些情况下它可能很有用。
【讨论】:
【参考方案4】:刚刚发现TypeConvert.ConvertFrom(object)
抛出异常的案例。
如果要将整数 0/1 转换为布尔值。使用TypeConvert.ConvertFrom(1)
或(0)
会出现异常。在这种情况下,Convert.ChangeType(1, System.Boolean)
有效。
【讨论】:
同样,TypeConvert.ConvertFrom()
会抛出异常,将 Int64 转换为 Int32 而不管值如何,而 Convert.ChangeType()
只要值不溢出就会成功。【参考方案5】:
我要晚 6 年才在这里发帖,因为我认为这是一个很好的问题,我对现有的答案并不满意。
静态Parse/TryParse
方法只能在当您想要从字符串转换为具有这些方法的类型 时使用。 (如果您预计转换可能会失败,请使用TryParse
)。
System.Convert
的意义在于,正如其documentation 所说,将从一种基本数据类型转换为另一种基本数据类型。请注意,使用 Convert 时,您还可以使用带有 Object
并自行确定如何转换它的方法。
至于System.ComponentModel.TypeConverter
,作为“typeconverter”堆栈溢出标记的documentation,它们主要用于与字符串之间的转换,当您想要提供文本表示时 用于设计器序列化或在属性网格中显示
【讨论】:
【参考方案6】:转换
Convert 类使用目标类型中实现的IConvertible 方法。
不幸的是,实现IConvertible
意味着编写大量样板代码,如果目标类型是结构,Convert.ChangeType 会导致装箱。
TypeConverterAttribute
TypeDescriptor.GetConverter 使用TypeConverterAttribute 并且恕我直言,它提供了更好的 API 来转换类型和更优雅的方式来使类型可转换。但它与Convert
类存在相同的性能问题,这是由于方法不是通用的。
解析/尝试解析
使用T.Parse
/T.TryParse
方法是从字符串创建对象的实际方法,因为它不涉及不必要的装箱。它们通常还具有重载,可以更好地控制如何解析字符串。
TryParse
方法允许您处理要解析的字符串是从用户输入或其他不保证格式正确的字符串获取的情况,而不会引发异常。
所以你应该调用类型的Parse
/TryParse
方法当你可以并且只有在编译时不知道目标类型时才回退到其他方法,即当您只有一个代表您的目标类型的 Type 对象。
您还可以查看我的名为ValueString 的小库,它可以找到最合适的类型解析方法并使用它来解析字符串。
【讨论】:
【参考方案7】:另一个迟到的答案。我有一个应用程序,我在其中使用了一些如下所示的代码:
var finalValue = Convert.ChangeType(sourceValue, targetProperty.PropertyType);
sourceValue
将是我想要的 string
表示,通常是 wrapper class
下的 primitive
。这种方式适用于常规数据类型。即使是整个班级。然而,有一天我愚蠢地决定将属性的数据类型更改为double
为可空的double?
,猜猜怎么着?轰隆隆!
从字符串到可空双精度的无效转换
这是您应该使用TypeConverter
类的完美场景,如下所示:
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,
【讨论】:
以上是关于TypeConverter vs. Convert vs. TargetType.Parse的主要内容,如果未能解决你的问题,请参考以下文章
TypeConverter() 在 Android 中的 Room 出现 TypeConverter 错误时具有私有访问权限
SQL Server cast() vs convert() [重复]