【问题标题】:Getting Input of a Required Type: Solution Using Generics?获取所需类型的输入:使用泛型的解决方案?
【发布时间】:2015-06-22 04:49:54
【问题描述】:

很久以前,在一个遥远的星系中,我在this question here 上发布了关于输入等的答案。

该问题涉及避免使用多个 ReadLine() 语句来获取用户输入以及绕过它来清理代码的方法。我使用提示方法发布了一个简单的答案,该方法显示提示并返回输入。但是,它总是返回字符串。现在,可以实现自己的解析来提取他们想要的信息,但是如果泛型可以简化事情并返回所需的类型呢?

我认为这很容易。所以我试着把它作为一个简单的练习来做。原来,我觉得我不够聪明(哎呀)。

我首先在 Generic SomeClass<T> like 中尝试了一个辅助方法

public static T getInput(String prompt, Type T)
{
    //some stuff about printing the prompt
    String input = Console.In.ReadLine();
    return (T)input;
}

你们中的许多人无疑会看到,这是错误的,并返回错误“无法将 String 转换为类型 T”。

我的下一个方法是使用SomeClass<T> where T : String 同样,你们中的许多人会在这里看到错误:字符串已密封。

所以:问题是,有没有办法使用我概述的方法和泛型来正确获取用户输入并以请求的类型(如 int、String 或可能是用户定义的类型)返回它?

【问题讨论】:

  • “我想避免总结它”——尽管您有偏好,但每个 Stack Overflow 问题都应该独立存在(当然,作为重复关闭的问题除外) .请为 this 问题添加足够的详细信息,以便无需阅读其他问题即可理解它。如果您认为该链接提供了一些附加价值,请随时将链接留在那里,但请不要以引用该链接的方式提出您的问题 必需
  • 好的。我即将离开去旅行,但我将把它编辑成一个独立的。另外,@PeterDuniho,感谢您的建议。我并不总是考虑独立问题之类的问题,我很感激能帮助其他人更好地理解我的节制。
  • 您甚至不能将string 转换为int,因此这不适用于简单的转换。此外,Type T 没有做任何事情.. 除了混淆代码。 (T) 指的是类型参数。
  • 请注意,根据现在的情况,我建议使用Convert.ChangeType(input, typeof(T))。但我不确定这就是你想要的,因为问题不清楚。
  • 你需要一个知道如何转换为字符串的类型 T...我不知道这是否可能,因为你不能继承字符串并且不能使用 where T : IStringCastable 因为字符串没有'不实现这个接口

标签: c# generics


【解决方案1】:

请注意,从字符串转换为某些类型非常依赖于文化设置。例如DateTime 解析将非常困难。对于数字、小数分隔符、货币符号等因文化而异。

当用户输入错误或提供无效输入时,应该有一个重试机制,通知用户。

static T ReadInput<T>(string prompt)
{
    return ReadInput<T>(prompt, CultureInfo.CurrentCulture);
}
static T ReadInput<T>(string prompt, IFormatProvider formatProvider)
{
    bool validInput = false;
    T result = default(T);
    Console.WriteLine("Prompt");
    while (!validInput)
    {
        try
        {
            result = (T)Convert.ChangeType(Console.ReadLine(), typeof (T), formatProvider);
            validInput = true;
        }
        catch
        {
            Console.WriteLine("Could not interpret value, please try again.");
        }
    }
    return result;
}

请注意,无法使此用户友好。考虑定义一个转换器接口,它可以在解析失败时提供错误消息并安全地尝试转换:

interface IConvertStringTo<T>
{
    bool TryGetValue(string input, IFormatProvider formatProvider, out T value);
    string ErrorMessage { get; }
}

class IntegerParser : IConvertStringTo<int>
{
    public bool TryGetValue(string input, IFormatProvider formatProvider, out int value)
    {
        return int.TryParse(input, NumberStyles.Integer, formatProvider, out value);
    }

    public string ErrorMessage
    {
        get { return "Please enter a number."; }
    }
}

【讨论】:

    【解决方案2】:

    根据 Tim Coker(作者为“Tuna Toksoz”)在https://stackoverflow.com/a/1833128/4780742 的回答,您可以使用TypeDescriptor 获得任何类型的转换器。 TypeDescriptor 优于 Convert.ChangeType 的原因是,如果实现了用户定义类的转换器,它可以适用于可空值和用户定义类。

    public static class TConverter
    {
        public static T ChangeType<T>(object value)
        {
            return (T)ChangeType(typeof(T), value);
        }
        public static object ChangeType(Type t, object value)
        {
            TypeConverter tc = TypeDescriptor.GetConverter(t);
            return tc.ConvertFrom(value);
        }
        public static void RegisterTypeConverter<T, TC>() where TC : TypeConverter
        {
    
            TypeDescriptor.AddAttributes(typeof(T), new TypeConverterAttribute(typeof(TC)));
        }
    }
    

    RegisterTypeConverter 让您在计划多次转换特定类型时不必使用反射。

    【讨论】:

      【解决方案3】:

      我认为Convert.ChangeType 可能适合这里的账单,尽管它会因输入错误而严重失败。 OP练习。

      public static T GetInput<T>(string prompt)
      {
          //some stuff about printing the prompt
          string input = Console.ReadLine();
          return (T)Convert.ChangeType(input, typeof(T));
      }
      

      那么现在:

      float a = GetInput<float>("enter a float:");
      

      您可能可以通过查看 this question 及其答案来强化代码。

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-11
      • 1970-01-01
      • 2021-12-10
      相关资源
      最近更新 更多