Answered How to return a nullable type object?

AndreiM

Member
Joined
Oct 9, 2020
Messages
7
Programming Experience
1-3
C# 7.3. I'm trying to have a method take a Type parameter and return its corresponding nullable. Like:

C#:
public static System.Type GetTypeNullable(System.Type t)
{
    return System.Nullable<t>;
}

This shows the error: 't?' is a type, which is not valid in the given context.
That's precisely my intention: to return the t?.

Also tried
C#:
return typeof(System.Nullable<t>);
 

Skydiver

Staff member
Joined
Apr 6, 2019
Messages
5,698
Location
Chesapeake, VA
Programming Experience
10+
Pay attention to the other error given by the compiler.
Error CS0118 't' is a variable but is used like a type

Anyway this works for me:
C#:
public static Type GetNullableType<T>() where T : struct
    => typeof(T?);
 

AndreiM

Member
Joined
Oct 9, 2020
Messages
7
Programming Experience
1-3
Thank you, that's so deceivingly simple, yet it didn't occur to me. I was so caught in finding a solution for my underlying problem and I've tried multiple ways all day long yesterday and that's how I got to ask this. I was looking for a way to return an object of type T?. And the root of this is searching for a way to return null regardless of T being a value or reference type. Like so:

C#:
public T GetSourceNode<T>(T sample)
{
    if(Validate(sample))
        return sample;
    else
        return null;
}
T could be anything, value type, reference type. One way is to use object as return type but consumer would have to cast it and this is not good.
 

jmcilhinney

C# Forum Moderator
Staff member
Joined
Apr 23, 2011
Messages
4,643
Location
Sydney, Australia
Programming Experience
10+
Thank you, that's so deceivingly simple, yet it didn't occur to me. I was so caught in finding a solution for my underlying problem and I've tried multiple ways all day long yesterday and that's how I got to ask this. I was looking for a way to return an object of type T?. And the root of this is searching for a way to return null regardless of T being a value or reference type. Like so:

C#:
public T GetSourceNode<T>(T sample)
{
    if(Validate(sample))
        return sample;
    else
        return null;
}
T could be anything, value type, reference type. One way is to use object as return type but consumer would have to cast it and this is not good.
I don't see how you could do that without declaring two separate methods because in one case you input T and output T while in the other case you input T and output T?. In the case of value types, the output is not the same as the input so you can't use the same method as for reference types.
 

AndreiM

Member
Joined
Oct 9, 2020
Messages
7
Programming Experience
1-3
That thing... that return type is not considered as part of the signature... otherwise I would use basic static polymorphism. Same with type constraints, if they would make the compiler aware, I'd have the same name for where T : struct and where T : class.
 

jmcilhinney

C# Forum Moderator
Staff member
Joined
Apr 23, 2011
Messages
4,643
Location
Sydney, Australia
Programming Experience
10+
That thing... that return type is not considered as part of the signature... otherwise I would use basic static polymorphism. Same with type constraints, if they would make the compiler aware, I'd have the same name for where T : struct and where T : class.
Yeah, I wasn't implying that you should overload a method because the parameters would not be different. You need two separate methods and you'll just have to call the right one based on the whether it's a value type or a reference type. The generic constraints you showed will prevent you calling the wrong one.
 

AndreiM

Member
Joined
Oct 9, 2020
Messages
7
Programming Experience
1-3
Using different names has to eventually merge into one name call inside the class. I need one name simply for polymorphism reasons.

Thank both of you for taking the time to help. It means a lot.
I'll rethink the model. Instead of T and T? I'll probably return a tuple that contains the T object and a bool like 'isNull'.
 

jmcilhinney

C# Forum Moderator
Staff member
Joined
Apr 23, 2011
Messages
4,643
Location
Sydney, Australia
Programming Experience
10+
In that case, could you perhaps write a method similar to all the TryParse methods, e.g.
C#:
public bool TryValidate<T>(ref T sample)
{
    if (Validate(sample))
        return true;

    sample = default;

    return false;
}
That's a ref parameter so you would lose the original value. If that's not a problem then this may be the way to go. There would probably be a better name for that method but you'd know that better than me.
 

AndreiM

Member
Joined
Oct 9, 2020
Messages
7
Programming Experience
1-3
Thanks @jmcilhinney but I want to return the object.
Speaking of default, the ability to return null for both value and reference types would work well alongside default. Imagine returning an "undefined" value from methods, for value types, just as null is for references. Just return (possibly a type agnostic) undefined. default would have been perfect. If only... I don't want to sound nitpicky but default represents for each value type, a very common, maybe the most common value, which is confusing, at least for me. Ideally all variables, value and reference, would be nullable but given the language, at least pick the most infrequent value (1) that wouldn't mess up the contiguity of values (2), so I'd say MaxValue. MinValue coincides with 0 for many types so it's a no-go.
I wish defaults could be custom defined per project but if I'm not mistaken default is currently about filling 0's in object's memory.
 

jmcilhinney

C# Forum Moderator
Staff member
Joined
Apr 23, 2011
Messages
4,643
Location
Sydney, Australia
Programming Experience
10+
I wish defaults could be custom defined per project but if I'm not mistaken default is currently about filling 0's in object's memory.
default is like Nothing in VB. It basically gives you the same value as an uninitialised variable of the type, i.e. the default value for that type. It's about filling zeroes in a variable's memory, not an object's memory. That's why default produces null for reference types: there is no object. Value type variables contain the object itself rather than a reference to an object, so that object is full of zeroes and it's up to the type how that is interpreted.
 

jmcilhinney

C# Forum Moderator
Staff member
Joined
Apr 23, 2011
Messages
4,643
Location
Sydney, Australia
Programming Experience
10+
I need one name simply for polymorphism reasons.
Do you though? You'd have to know what the type was at design time in order to call a generic method so, unless you're passing a variable of an interface type that you are implementing in a class and a structure, you'd have to know whether it's a value type or reference type. Any derived type of a reference type is still a reference type so that's no issue. I suspect that you may be imagining a problem that doesn't exist.
 

AndreiM

Member
Joined
Oct 9, 2020
Messages
7
Programming Experience
1-3
Of course there is always a way to get a problem over with and "need" means anything between "I need food to survive" and "I need you to believe in me" :) But when I have to solve an issue, even if I know an immediate solution I try to do a little research even if it takes extra time. This way I'd find a better approach, fit for other use cases as well.
Ok, sample, the parameter, can be anything. I suppose I could get it done with separate names based on nullable/non-nullable. But I just want to do it in a less blunt way. i.e. I want polymorphism. The class is meant to be consumed by other, external users. And apart from the case above I also need the <same name> implementation for an indexer of the T type in the class. In which case I don't even have a name. And thank you for pointing out the struct/class/interface use case. And finally, for completion, a whole range of cases that thank God, I don't have to implement. (Yet). Extension methods + generics. Consider:

C#:
public T GetMedian(this List<T> ts)
{
    return ts[t.Count/2];
}
What if the return is null? I could have GetMedianNullable and GetMedianNonNullable, not cool.
 

Skydiver

Staff member
Joined
Apr 6, 2019
Messages
5,698
Location
Chesapeake, VA
Programming Experience
10+
It can only be null if it is a list of references types. A list of value types will never be null.

And so what if it is null? That's the value that is stored in the list. Why would you have to have a separate method for something that may return null and something which may not?

I feel that a lot of this worry about a null object would go away if you used the latest C# feature that ensures no object can be null unless you explicitly say that it can be null.
 
Top Bottom