是否有任何通用的 Parse()函数可以使用 Parse 将字符串转换为任何类型?

我希望基于泛型返回类型将字符串转换为类似于 intdatelong的泛型类型。

基本上是一个类似于 Parse<T>(String)的函数,它返回类型为 T的项。

例如,如果传递了 int 函数,那么该函数应该在内部执行 int.parse

50848 次浏览

System.Convert.ChangeType

As per your example, you could do:

int i = (int)Convert.ChangeType("123", typeof(int));
DateTime dt = (DateTime)Convert.ChangeType("2009/12/12", typeof(DateTime));

To satisfy your "generic return type" requirement, you could write your own extension method:

public static T ChangeType<T>(this object obj)
{
return (T)Convert.ChangeType(obj, typeof(T));
}

This will allow you to do:

int i = "123".ChangeType<int>();

System.Convert.ChangeType does not convert to any type. Think of the following:

  • nullable types
  • enums
  • Guid etc.

These conversions are possible with this implementation of ChangeType.

There are a couple of conventions in the .NET to convert objects of one type to another.

But these methods are much slower than your typical T.Parse(string), cause boxing and involve lots of allocations each time you want to convert a single value.

For ValueString, I chose to find a suitable, static parsing method of the type using reflection, build a lambda expression calling it and cache the compiled delegate for future use (See this answer for an example).

It also fallbacks to the ways I mentioned above if the type doesn't have a suitable parsing method (See the performance section in the readme).

var v = new ValueString("15"); // struct
var i = v.As<int>(); // Calls int.Parse.

Well looks like I am too late for answering on this thread. But here is my implementation:

Basically, I have created an Extention method for the Object class. It handles all the types, i.e nullable, classes, and struct.

 public static T ConvertTo<T>(this object value)
{
T returnValue;


if (value is T variable)
returnValue = variable;
else
try
{
//Handling Nullable types i.e, int?, double?, bool? .. etc
if (Nullable.GetUnderlyingType(typeof(T)) != null)
{
TypeConverter conv = TypeDescriptor.GetConverter(typeof(T));
returnValue = (T) conv.ConvertFrom(value);
}
else
{
returnValue = (T) Convert.ChangeType(value, typeof(T));
}
}
catch (Exception)
{
returnValue = default(T);
}


return returnValue;
}

cleaner version of Pranay's answer

public static T ConvertTo<T>(this object value)
{
if (value is T variable) return variable;


try
{
//Handling Nullable types i.e, int?, double?, bool? .. etc
if (Nullable.GetUnderlyingType(typeof(T)) != null)
{
return (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(value);
}


return (T)Convert.ChangeType(value, typeof(T));
}
catch (Exception)
{
return default(T);
}
}

As of C# 11 and .Net 7, this is now possible and supported thanks to static methods on interfaces.

The new IParsable<TSelf> provides a static Parse method:

abstract static TSelf Parse(string s, IFormatProvider? provider);

All the common value types (int, decimal, Guid, etc) implement this interface, but with one exception: Nullable<T> doesn't, as obviously the T in nullable cannot be assumed to implement IParsable<T>. But this shouldn't be an issue in practice (example provided below).

Here's a simple extension method to make use of it:

public static T Parse<T>(this string s, IFormatProvider? provider = null) where T : IParsable<T>
{
return T.Parse(s, provider);
}

So, for example, a call of myString.Parse<int> will directly call int.Parse without boxing, or the need for checking the type at runtime.

Example usage:

string s = "5";
int i = s.Parse<int>();
double d = s.Parse<double>();


// Need Nullable<T> support? Just use the null-conditional operator.
string? s2 = null;
decimal? d2 = s2?.Parse<decimal>();