使用“Convert.ChangeType()”将System.String一般转换为任何复杂类型

时间:2011-03-23 07:00:34

标签: c# string type-conversion

我尝试将用户输入一般转换为简单或复杂类型:

class Program
{
  static void Main(string[] args)
  {
    Console.WriteLine("Welcome, please provide the following info... Confirm with <RETURN>!");
    Console.WriteLine();    

    Console.Write("Name (e.g. 'Peggy Sue'): ");
    var user = GetUserInput<User>(Console.ReadLine());

    Console.WriteLine();
    Console.WriteLine();
    Console.WriteLine("Hi {0}, nice to meet you!", user.Forename);
    Console.WriteLine();

    Console.Write("Age: ");
    user.Age = GetUserInput<ushort>(Console.ReadLine());

    Console.WriteLine();
    Console.WriteLine("Thanks and goodbye!");
    Console.WriteLine("Press <RETURN> to quit...");
    Console.ReadLine();
  }

  static T GetUserInput<T>(string data)
  {
    return (T) Convert.ChangeType(data, typeof (T));
  }
}

class User
{
  public User(string name)
  {
    var splitted = name.Split(' ');
    Forename = splitted[0];
    Lastname = splitted[1];
  }

  public static implicit operator User (string value)
  {
    return new User(value);
  }

  public static explicit operator string (User value)
  {
    return string.Concat(value.Forename, " ", value.Lastname);
  }

  public string Forename { get; private set; }
  public string Lastname { get; private set; }

  public ushort Age { get; set; }
}

为了转换到我的“User”类,我总是得到异常“从'System.String'到'ConsoleApplication1.User'的无效转换。”。有谁知道如何解决这个问题?

如果我尝试这样的事情(不是一般性的),那就完美了:

Console.WriteLine((string) ((User) "Peggy Sue"));

4 个答案:

答案 0 :(得分:6)

不,Convert.ChangeType仅适用于一组固定的类型,我相信......或者如果原始对象实现IConvertible,它可以调用IConvertible.ToType。这意味着您可能在您的IConvertible课程中实施User并拥有

Convert.ChangeType(user, typeof(string))

工作,但不会反过来工作。

您是否有需要转换的固定类型?如果是这样,您可以使用Dictionary<Type, Func<string, object>>填充转化代理。然后你只需要调用适当的转换并转换返回值。这很难看,但可能是你最好的选择。

答案 1 :(得分:5)

这里的一个选项可能是将TypeConverter与您关注的类型相关联(您可以在编译时通过[TypeConverter(...)]执行此操作,或者如果您不控制,则可以在运行时执行此操作类型)。

然后是:

TypeConverter conv = TypeDescriptor.GetConverter(typeof(T));
T obj = (T)conv.ConvertFromString(text); // or ConvertFromInvariantString

答案 2 :(得分:2)

我修好了。检查一下:

class Program
{
  static void Main(string[] args)
  {
    Console.WriteLine("Welcome, please provide the following info... Confirm with <RETURN>!");
    Console.WriteLine();

    Console.Write("Name (e.g. 'Peggy Sue'): ");
    var user = GetUserInput<User>(Console.ReadLine());

    Console.WriteLine();
    Console.WriteLine();
    Console.WriteLine("Hi {0}, nice to meet you!", user.Forename);
    Console.WriteLine();

    Console.Write("Age: ");
    user.Age = GetUserInput<ushort>(Console.ReadLine());

    Console.WriteLine();
    Console.WriteLine("Thanks and goodbye!");
    Console.WriteLine("Press <RETURN> to quit...");
    Console.ReadLine();
  }

  static T GetUserInput<T>(string data)
  {
    TypeConverter conv = TypeDescriptor.GetConverter(typeof(T));
    return (T) conv.ConvertFromInvariantString(data);
  }
}

[TypeConverter(typeof(UserConverter))]
class User
{
  public User(string name)
  {
    var splitted = name.Split(' ');
    Forename = splitted[0];
    Lastname = splitted[1];
  }

  public static explicit operator User (string value)
  {
    return new User(value);
  }

  public static explicit operator string (User value)
  {
    return string.Concat(value.Forename, " ", value.Lastname);
  }

  public string Forename { get; private set; }
  public string Lastname { get; private set; }

  public ushort Age { get; set; }
}

class UserConverter : TypeConverter
{
  public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
  {
    return (typeof(string) == sourceType);
  }

  public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
  {
    if (value is string)
    {
      return (User)(value as string);
    }

    return null;
  }
}

答案 3 :(得分:0)

如果您希望转换为数字类型,我更喜欢更简洁和意图曝光:

decimal.Parse(someString)

或者,在您的示例中:

new User(userName)

没有理由创建一个完整的方法(或类,如果您将来决定“使这个可重用”)只是为了包装一个演员。当语言已经采用不太透明的方式来表达代码的意图时,尤其如此。