【问题标题】:How do I make the return type of a method generic?如何使方法的返回类型通用?
【发布时间】:2012-04-06 04:09:46
【问题描述】:

有没有办法使这个方法通用,以便我可以返回一个字符串、布尔值、整数或双精度值?现在,它返回的是一个字符串,但如果它能够找到“true”或“false”作为配置值,我想返回一个 bool 例如。

    public static string ConfigSetting(string settingName)
    {  
         return ConfigurationManager.AppSettings[settingName];
    }

【问题讨论】:

  • 有没有办法让你知道每个设置是什么类型?
  • 我认为您真正想问的问题是“如何使我的应用程序配置成为强类型?”不过,我已经很久没有写出正确的答案了。
  • 是的,理想情况下我不想将类型传递给方法。我只会有我提到的4种类型。所以如果设置了“true”/“false”,我希望这个函数返回一个布尔值(不需要将它传递给方法),我可能可以将 int 和 double 组合成 double,其他一切都应该是一个字符串。已经回答的内容可以正常工作,但我每次都需要传递类型,这可能很好。
  • 您的评论听起来像是您在要求一个方法,该方法将返回一个强类型的 bool(或字符串,或 int,或者你有什么)在运行时基于为设置名称键检索的实际数据。 C# 不会为你这样做;您无法在编译时知道该值的类型。换句话说,这是动态类型,而不是静态类型。如果您使用 dynamic 关键字,C# 可以为您做到这一点。这会带来性能成本,但对于读取配置文件,性能成本几乎可以肯定是微不足道的。

标签: c# .net generics return-type


【解决方案1】:

你需要把它变成一个泛型方法,像这样:

public static T ConfigSetting<T>(string settingName)
{  
    return /* code to convert the setting to T... */
}

但是调用者必须指定他们期望的类型。然后你可以使用Convert.ChangeType,假设所有相关类型都受支持:

public static T ConfigSetting<T>(string settingName)
{  
    object value = ConfigurationManager.AppSettings[settingName];
    return (T) Convert.ChangeType(value, typeof(T));
}

我并不完全相信这一切都是个好主意,请注意...

【讨论】:

  • /* 将设置转换为 T... */ 的代码如下:)
  • 这是否不需要您知道您希望获得的设置类型,这可能是不可能的。
  • @thecoshman:会的,但如果你不这样做,那么你会如何处理返回的值?
  • 虽然这个答案当然是正确的,并且您注意到满足了 OP 的要求,但可能值得一提的是,单独方法的旧方法(ConfigSettingStringConfigSettingBool 等)具有更短、更清晰、更专注的方法主体的优势。
  • 如果不建议这样做,那么泛型返回类型的目的是什么?
【解决方案2】:

你可以使用Convert.ChangeType():

public static T ConfigSetting<T>(string settingName)
{
    return (T)Convert.ChangeType(ConfigurationManager.AppSettings[settingName], typeof(T));
}

【讨论】:

    【解决方案3】:

    有很多方法可以做到这一点(按优先级列出,特定于 OP 的问题)

    1. 选项 1:直接方法 - 为您期望的每种类型创建多个函数,而不是使用一个通用函数。

      public static bool ConfigSettingInt(string settingName)
      {  
           return Convert.ToBoolean(ConfigurationManager.AppSettings[settingName]);
      }
      
    2. 选项 2:当您不想使用花哨的转换方法时 - 将值转换为对象,然后转换为泛型类型。

      public static T ConfigSetting<T>(string settingName)
      {  
           return (T)(object)ConfigurationManager.AppSettings[settingName];
      }
      

      注意 - 如果演员表无效(您的情况),这将引发错误。如果您不确定类型转换,我不建议您这样做,而是选择选项 3。

    3. 选项 3:具有类型安全性的泛型 - 创建一个泛型函数来处理类型转换。

      public static T ConvertValue<T,U>(U value) where U : IConvertible
      {
          return (T)Convert.ChangeType(value, typeof(T));
      } 
      

      注意 - T 是预期的类型,注意这里的 where 约束(U 的类型必须是 IConvertible 才能避免错误)

    【讨论】:

    • 为什么在U 中将第三个选项设为通用?这样做没有任何意义,而且它使方法更难调用。只需接受 IConvertible 即可。我认为这个问题不值得包含第二个选项,因为它没有回答所提出的问题。您可能还应该重命名第一个选项中的方法...
    【解决方案4】:

    您必须将方法返回值的类型转换为在调用期间传递给方法的通用类型。

        public static T values<T>()
        {
            Random random = new Random();
            int number = random.Next(1, 4);
            return (T)Convert.ChangeType(number, typeof(T));
        }
    

    您需要为通过该方法返回的值传递一个可强制类型转换的类型。

    如果您希望将一个不可类型转换的值返回给您传递的泛型类型,您可能必须更改代码或确保您为方法的返回值传递可转换的类型。因此,不推荐这种方法。

    【讨论】:

    • 点对点 - 对我来说,最后一行 return (T)Convert.ChangeType(number, typeof(T)); 正是我所缺少的 - 干杯
    【解决方案5】:

    创建一个函数,并将 put 参数作为泛型类型传递。

     public static T some_function<T>(T out_put_object /*declare as Output object*/)
        {
            return out_put_object;
        }
    

    【讨论】:

    • 这对于一些用例来说实际上非常聪明。就像从数据库中提取数据一样。你知道你会得到一个 T 类型的数据列表。加载方法只是不知道你现在想要什么类型的 T。因此,只需将一个新的 List 传递给它,该方法就可以完成它的工作并在返回之前填充列表。不错!
    【解决方案6】:

    请尝试以下代码:

    public T? GetParsedOrDefaultValue<T>(string valueToParse) where T : struct, IComparable
    {
     if(string.EmptyOrNull(valueToParse))return null;
      try
      {
         // return parsed value
         return (T) Convert.ChangeType(valueToParse, typeof(T));
      }
      catch(Exception)
      {
       //default as null value
       return null;
      }
     return null;
    }
    

    【讨论】:

      【解决方案7】:
       private static T[] prepareArray<T>(T[] arrayToCopy, T value)
          {
              Array.Copy(arrayToCopy, 1, arrayToCopy, 0, arrayToCopy.Length - 1);
              arrayToCopy[arrayToCopy.Length - 1] = value;
              return (T[])arrayToCopy;
          }
      

      我在整个代码中都在执行此操作,并且想要一种将其放入方法中的方法。我想在这里分享这个,因为我不必使用 Convert.ChangeType 作为我的返回值。这可能不是最佳实践,但对我有用。此方法接受一个泛型类型的数组和一个要添加到数组末尾的值。然后复制该数组,去掉第一个值,并将该方法中的值添加到数组的末尾。最后一件事是我返回了泛型数组。

      【讨论】:

        猜你喜欢
        • 2010-10-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-12
        • 2018-02-23
        • 2020-10-03
        • 1970-01-01
        • 1970-01-01
        • 2020-11-22
        相关资源
        最近更新 更多