【问题标题】:Convert from string to any basic type从字符串转换为任何基本类型
【发布时间】:2018-03-19 05:59:31
【问题描述】:

我有一个string 和一个Type,我想返回转换为Typestring 值。

public static object StringToType(string value, Type propertyType)
{
    return Convert.ChangeType(value, propertyType, CultureInfo.InvariantCulture);
}

这会返回一个object,我可以在属性集值调用中使用它:

public static void SetBasicPropertyValueFromString(object target,
                                                   string propName,
                                                   string value)   
{
  PropertyInfo prop = target.GetType().GetProperty(propName);
  object converted = StringToType(value, prop.PropertyType);
  prop.SetValue(target, converted, null);
}

这适用于大多数基本类型,可空值除外。

[TestMethod]
public void IntTest()
{ //working
    Assert.AreEqual(1, ValueHelper.StringToType("1", typeof (int)));
    Assert.AreEqual(123, ValueHelper.StringToType("123", typeof (int)));
}

[TestMethod]
public void NullableIntTest()
{ //not working
    Assert.AreEqual(1, ValueHelper.StringToType("1", typeof (int?)));
    Assert.AreEqual(123, ValueHelper.StringToType("123", typeof (int?)));
    Assert.AreEqual(null, ValueHelper.StringToType(null, typeof (int?)));
}

NullableIntTest 在第一行失败:

System.InvalidCastException:从 'System.String' 到 'System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]' 的无效转换。

我很难确定该类型是否可以为空并更改 StringToType 方法的行为。

我所追求的行为:

如果字符串为null或空,则返回null,否则按照不可为空的类型进行转换。

结果

就像基里尔的回答一样,只有一个ChangeType 电话。

public static object StringToType(string value, Type propertyType)
{
    var underlyingType = Nullable.GetUnderlyingType(propertyType);
    if (underlyingType != null)
    {
        //an underlying nullable type, so the type is nullable
        //apply logic for null or empty test
        if (String.IsNullOrEmpty(value)) return null;
    }
    return Convert.ChangeType(value,
                              underlyingType ?? propertyType,
                              CultureInfo.InvariantCulture);
}

【问题讨论】:

  • 你可以让你的方法通用:public static object StringToType<T>(string value) where T : struct ...
  • @KarelFrajtak Na,由于它的调用方式,请参见第二个代码片段。 prop.PropertyType 来自反射,所以直到运行时才知道。
  • 您的if 支票不太正确。您的特殊情况不应该适用于 any 泛型类型,而应该只是适用于 Nullable<T>,因为它们的装箱方式不同。
  • 好的,但它也可以是一个选项;)
  • @Servy 是的,我已经更新了。现在基于基里尔的回答。

标签: c#


【解决方案1】:

您不能对可空类型使用 Convert.ChangeType,因为它不是从 IConvertible 继承的。你应该重写你的方法。

public static object StringToType(string value, Type propertyType)
{
   var underlyingType = Nullable.GetUnderlyingType(propertyType);
   if(underlyingType == null)
          return Convert.ChangeType(value, propertyType,  CultureInfo.InvariantCulture);
   return String.IsNullOrEmpty(value)
          ? null
          : Convert.ChangeType(value, underlyingType, CultureInfo.InvariantCulture);
}

【讨论】:

  • 这段代码有一个错误。此代码可用于一般情况,这意味着有人可能正在使用该代码将字符串值转换为字符串。如果字符串为空,则返回 null 而不是空
  • 这段代码没有错误。要求是:“如果字符串为空或空,则返回空,否则按照不可为空的类型进行转换”。此代码按要求运行。
  • 对于枚举类型,它会抛出一个 InvalidCastException,并且需要一个附加条件,例如回答 here
【解决方案2】:
public static object StringToType(string value, Type propertyType)
{
   var underlyingType = Nullable.GetUnderlyingType(propertyType);
   return underlyingType == null ? Convert.ChangeType(value, propertyType, CultureInfo.InvariantCulture) : Convert.ChangeType(value, underlyingType, CultureInfo.InvariantCulture);
}

【讨论】:

  • 很好,只是缺少处理 null 或空字符串的逻辑。
  • 你写的很好解释Servylink
【解决方案3】:

试试这个:

prop.IsGenericType && Nullable.GetUnderlyingType(prop) == value.GetType()

【讨论】:

    【解决方案4】:

    这里的问题是ChangeType的返回值,以及你的方法,都是object。当您将任何可空类型装入object 时,它不会将可空类型装箱。如果该值在运行时实际上为 null,则将 null 框起来,如果它有值,则将实际基础值(而不是可为 null 的版本)框起来。

    int? i = 5;
    object o = i;
    Type t = o.GetType();//will be `int`, not `Nullable<int>`
    

    这不会发生在任何其他类型的一般情况下; Nullable&lt;T&gt; 具有执行此操作的特殊编译器支持。您基本上还需要在代码中使用特殊情况 Nullable;如果您的方法传递了Nullable 类型,您需要首先检查对象是否有null,如果不是null,请改用Nullable 的底层类型。

    【讨论】:

      【解决方案5】:

      Kirill Bestemyanov 的 sn-p 帮助下的代码:

      public static object StringToType<T>(string value)
      {
         return StringToType(value, typeof(T));
      }
      
      public static object StringToType(string value, Type propertyType)
      {
         var underlyingType = Nullable.GetUnderlyingType(propertyType);
         if(underlyingType == null)
           return Convert.ChangeType(value, propertyType, CultureInfo.InvariantCulture);
         return String.IsNullOrEmpty(value)
           ? null
           : Convert.ChangeType(value, underlyingType, CultureInfo.InvariantCulture);
      }
      

      和用法(WL 只是写入控制台)。你是对的,泛型方法不能使用int? 作为泛型参数。

      WL(StringToType("1", typeof (int?))); // -> 1
      WL(StringToType<int>("1"));           // -> 1
      WL(StringToType<int?>("1"));          // error, not compilable
      WL(StringToType<Nullable<int>>("1")); // -> 1
      

      【讨论】:

      • 我的意思是你不能像这样使用反射,请参阅我的 SetBasicPropertyValueFromString 方法了解它必须如何使用。
      • 你是对的,但在测试中你没有使用你描述的方式。一种方法在代码中有用,另一种在测试中有用。我不是告诉你必须按照我的方式去做,我只是在扩展你的想法。
      【解决方案6】:

      您必须为每种要支持的类型使用适当的转换方法。

      int parsedInt;
      int.TryParse("1", out parsedInt);
      
      double parsedDouble;
      double.TryParse("0.0d", out parsedDouble);
      

      编译器不可能根据字符串的内容来判断类型。有关从字符串类型转换为标量类型的更多信息,请参阅以下链接:http://msdn.microsoft.com/en-us/library/bb397679.aspxhttp://msdn.microsoft.com/en-us/library/bb384043.aspx

      【讨论】:

      • 当然这是不可能的,但我并不是要求编译器计算出类型。我的目标类型在Type propertyType
      猜你喜欢
      • 2019-03-06
      • 2012-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-29
      • 1970-01-01
      • 2019-02-23
      相关资源
      最近更新 更多