"Promote" generic type to Nullable in C#?
c#, generics, metaprogramming, nullable, type-traits
Solution
Doesn't directly answer the question as posed, but I'd write this:
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;
}
So the bulk of the code exists only once - and you can even now actually have the calling code choose to have `null` as a default value, if it so chooses.
Even if you could create the parameter declaration you wanted, this line would still be an issue:
return default_value;
If it turned out that `default_value` was a `T?` rather than a `T`, then the above code doesn't work. Even if you do a cast:
return (T)default_value;
there's still an issue - that to cast from `T?` to `T`, the compiler actually has to insert a call to obtain the `Value` property of the nullable. But that call wouldn't be valid if the type of `default_value` was just `T`.
In C# Generics, the compiler has to create one piece of IL for the method. There's no way to insert an optional piece of code that may access `Value`.
Problem
Given a generic type `T` in C#, I wonder how to acquire type `Q`, which is equal to `T?` for non-nullable `T`, and `T` for already nullable `T`. The question arose from real code. I want to unify access to parameters passed through query string in my ASP.NET application. And I want to specify a default value of the same type, but ensure `null` can be passed as a default value. ``` 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)); } ``` Currently I'm forced having two overloads of the `FetchValue` - one without default value, and one with it: ``` public static T FetchValue<T>(string name); public static T FetchValue<T>(string name, T default_value); ``` It works fine, but I wonder whether it is possible to merge both functions like this. In C++ I would use type-traits, like `PromoteNullable<T>::type` with two specializations of `PromoteNullable` for both nullable and non-nullable types. But what about C#?