在C#中"推广"泛型类型为Nullable?

Mik*_*ail 8 c# generics nullable metaprogramming type-traits

给定TC#中的泛型类型,我想知道如何获取类型Q,它等于T?非可空类型T,并且T已经可以为空T.

问题来自真实的代码.我想统一访问我的ASP.NET应用程序中通过查询字符串传递的参数.我想指定相同类型的默认值,但确保null可以作为默认值传递.

public static T FetchValue<T>(
   string name, 
   <T? for non-nullable, T otherwise> default_value = null)  // How to write this?
{
  var page = HttpContext.Current.Handler as Page;

  string str = page.Request.QueryString[name];

  if (str == null)
  {
    if (default_value == null)
    {
      throw new HttpRequestValidationException("A " + name + " must be specified.");
    }
    else
    {
      return default_value;
    }
  }

  return (T)Convert.ChangeType(str, typeof(T));
}
Run Code Online (Sandbox Code Playgroud)

目前我被迫有两个重载FetchValue- 一个没有默认值,一个有它:

public static T FetchValue<T>(string name);
public static T FetchValue<T>(string name, T default_value);
Run Code Online (Sandbox Code Playgroud)

它运行正常,但我想知道是否可以合并这两个函数.

在C++中,我会用类型特征,喜欢PromoteNullable<T>::type用两个专业PromoteNullable的都为空的和非可空类型.但是C#怎么样?

Dam*_*ver 3

没有直接回答所提出的问题,但我会这样写:

    public static T FetchValue<T>(string name)
    {
        T value;
        if (TryFetchValue(name, out value))
            return value;
        throw new HttpRequestValidationException("A " + name + " must be specified.");
    }

    public static T FetchValue<T>(string name, T default_value)
    {
        T value;
        if (TryFetchValue(name, out value))
            return value;
        return default_value;
    }

    private static bool TryFetchValue<T>(
         string name,
         out T value)
    {
        var page = HttpContext.Current.Handler as Page;

        string str = page.Request.QueryString[name];

        if (str == null)
        {
            value = default(T);
            return false;
        }

        value = (T)Convert.ChangeType(str, typeof(T));
        return true;
    }
Run Code Online (Sandbox Code Playgroud)

因此,大部分代码只存在一次 - 即使现在您实际上也可以让调用代码选择将其作为null默认值(如果它选择的话)。


即使您可以创建所需的参数声明,这一行仍然是一个问题:

return default_value;
Run Code Online (Sandbox Code Playgroud)

如果结果default_value是 aT?而不是 a T,那么上面的代码就不起作用。即使你做了演员:

return (T)default_value;
Run Code Online (Sandbox Code Playgroud)

仍然存在一个问题 - 要从T?to转换T,编译器实际上必须插入一个调用来获取可Value为空的属性。default_value但如果 的类型只是,那么该调用将无效T

在 C# 泛型中,编译器必须为方法创建一段 IL。无法插入可以访问Value.