如何使方法的返回类型通用?


165

有没有办法使此方法通用,以便我可以返回字符串,bool,int或double?现在,它正在返回一个字符串,但是如果它能够找到“ true”或“ false”作为配置值,那么我想返回一个布尔值。

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

有没有办法让您知道每种设置的类型?
thecoshman 2012年

2
我认为您真正要问的问题是“如何使我的应用程序配置为强类型?” 不过,自从我一起写一个正确的答案以来,已经太久了。
西蒙(Simon)

是的,理想情况下,我不需要将类型传递给方法。我将只提到我提到的4种类型。因此,如果设置了“ true” /“ false”,则我希望此函数返回一个布尔值(无需将其传递给方法),我可能可以将int和double组合成double,而其他所有内容都应该是字符串。已经回答的内容可以正常工作,但是我每次都需要传递类型,这可能很好。
MacGyver 2012年

3
您的评论听起来像您在要求一种方法,该方法将在运行时根据为设置名称键检索的实际数据返回强类型的布尔值(或字符串,int或您拥有的内容)。C#不会为您这样做;您无法在编译时知道该值的类型。换句话说,这是动态类型,而不是静态类型。如果您使用dynamic关键字,C#可以为您做到这一点。这样做会有性能成本,但是对于读取配置文件而言,性能成本几乎可以忽略不计。
phoog 2012年

Answers:


353

您需要使其成为通用方法,如下所示:

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));
}

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


21
/ *代码将设置转换为T ... * /,然后跟随整本小说:)
Adrian Iftode 2012年

1
这是否不要求您知道希望获得的设置类型,而这可能是不可能的。
thecoshman 2012年

2
@thecoshman:可以,但是如果您不这样做,该如何处理返回的值?
乔治·达基特

5
虽然这个答案当然是正确的,正如你注意满足OP的请求时,它可能是值得一提的是单独的方法(老方法ConfigSettingStringConfigSettingBool等等)有方法体的优势会更短,更清晰,重点更明确。
phoog 2012年

4
如果不建议这样做,那么通用返回类型的目的是什么?
bobbyalex

29

您可以使用Convert.ChangeType()

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

13

有很多方法可以做到这一点(按优先级列出,特定于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才能使我们免于错误)


4
为什么要使第三个选项通用U?这样做是没有意义的,这会使该方法难以调用。只需接受IConvertible。考虑到它没有回答所提出的问题,我认为不值得为该问题包括第二个选项。您可能还应该在第一个选项中重命名该方法...
Jon Skeet

7

您必须将方法的返回值类型转换为在调用过程中传递给方法的泛型类型。

    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));
当场

1

创建一个函数,并传递一般类型的put参数。

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

在一些用例中,这实际上是相当聪明的。就像从数据库中提取数据一样。您知道您将获得T类型的数据列表。加载方法只是不知道您现在想要哪种T类型。因此,只需将新的List <WantedObject>传递给此方法,该方法就可以完成它的工作并在返回列表之前填充列表。真好!
Marco Heumann

0

请尝试以下代码:

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;
}

-1
 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作为返回值。这可能不是最佳做法,但对我有用。此方法采用通用类型的数组,并将一个值添加到该数组的末尾。然后在删除第一个值的情况下复制该数组,并将获取到方法中的值添加到数组的末尾。最后一件事是我返回通用数组。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.