Why does nullable KeyValuePair<,> have no key property? - c#

I have the following:
KeyValuePair<string, string>? myKVP;
// code that may conditionally do something with it
string keyString = myKVP.Key;
// throws 'System.Nullable<System.Collections.Generic.KeyValuePair<string,string>>'
// does not contain a definition for 'Key'
I'm sure there is some reason for this as I can see that the type is nullable. Is it because I am trying to access the key when null could cause bad things to happen?

Try this instead:
myKVP.Value.Key;
Here is a stripped down version of System.Nullable<T>:
public struct Nullable<T> where T: struct
{
public T Value { get; }
}
Since the Value property is of type T you must use the Value property to get at the wrapped type instance that you are working with.
Edit: I would suggest that you check the HasValue property of your nullable type prior to using the Value.
if (myKVP.HasValue)
{
// use myKVP.Value in here safely
}

This is because nullable types can be assigned null value or the actual value, hence you have to call ".value" on all nullable types. ".value" will return the underlying value or throw a System::InvalidOperationException.
You can also call ".HasValue" on nullable type to make sure that there is value assigned to the actual type.

Related

Casting object? to a generic type that may or may not be nullable

I'm trying to convert a project to use nullable reference types, but I'm running into an issue. In my project, I have a place where I get an object? that needs to be cast to a generic type T before adding it to a collection. The type T could be anything; a nullable reference type, a non-nullable reference type, or a value type. This isn't known at compile time.
So, let's say I have the following code (toy example):
static T Convert<T>(object? value)
{
return (T)value;
}
This causes the compiler to complain that value may be null, and that the return of the function may be null. That's fair enough, since if T is non-nullable and value is null, this wouldn't be allowed. I thought maybe this would work:
static T Convert<T>(object? value)
{
if (value == null)
return default;
else
return (T)value;
}
But this has the same problem: if T is a non-nullable reference type, default is still null, which still violates the constraint.
Making the function return T? is not a solution, because in the case of value types, I don't want to use Nullable<T>.
I thought about throwing an exception if value is null, but I want to allow null if T is nullable. So I'd only want to throw that if T is non-nullable, and that kind of generic specialization doesn't seem possible in C#.
The context here is that I'm using a TypeConverter, and unfortunately the result of conversion is allowed to return null.
Is there a good way to handle this situation?
If you use C# 9.0 or higher, you can use return type of T? without need to resort to Nullable<T>. For generics in non-nullable context there is special set of rules, detailed here.
If the type argument for T is a value type, T? references the same value type, T. For example, if T is an int, the T? is also an int.
You can check GetType() of T with simple console application. If T is int, return type will be System.Int32, not Nullable<System.Int32>.
#nullable enable
using System;
public class Program
{
public static void Main()
{
var result = Convert<int>(null);
Console.WriteLine(result); // Prints: 0
Console.WriteLine(result.GetType().FullName); // Prints: System.Int32
}
static T? Convert<T>(object? value)
{
if (value is null)
return default(T);
return (T)value;
}
}
C# Playground example here.

How do I tell the compiler about my nullable c# generic constraints?

I've got an editor that lets the user edit the "simple" properties of objects (int, string, DateTime, etc.), so it iterates through the properties and then constructs for each simple property an object to support the editing:
#nullable enable
public class DataNode<T>
{
protected PropertyInfo Prop;
protected object Source;
protected T Value;
protected bool Modified;
public DataNode(PropertyInfo prop, object source)
{
Prop = prop;
Source = source;
object? value = prop.GetValue(source);
if (value is T t)
Value = t;
else
Value = default;
Modified = false;
}
public virtual bool IsValid()
{
return true;
}
public void Save()
{
if (Modified)
{
Prop.SetValue(Source, Value);
Modified = false;
}
}
}
I then have subclasses for specific properties - for example, if there's an int property where I don't want the user to be able to enter a negative value, I can create a specific subclass:
public class NonNegativeIntNode : DataNode<int>
{
public NonNegativeIntNode (PropertyInfo prop, object source)
: base(prop, source)
{
}
public override bool IsValid()
{
return Value >= 0;
}
}
So that all works fine, and before you ask:
The selection of which DataNode class to use is controlled by custom attributes on the properties
The DataNode does more than this that I've left out for simplicity. For example the BoolDataNode class knows that to edit this value it should use a checkbox
The problem is that the compiler is grumbling that "Value = default;" is a possible null reference assignment, and that the DataNode constructor might be exiting with a null value for 'Value'.
I can keep the compiler happy by defining Value as "protected T? Value" but that adds unnecessary complication elsewhere to check for a null value when I know darn well that inside BoolDataNode that Value will never be null.
I tried splitting DataNode into two classes - NullableDataNode and NonNullableDataNode - but inside NonNullableDataNode, even though I specify "where T: notnull", the compiler is still worried about 'default'
It seems like saying "where T: notnull" means "I am never going to set Value to null" where what I want to tell the compiler is "T is a type that cannot be null" (like bool)
Is there a way to reassure the compiler that all is well, without simply turning off all the nullability warnings with pragmas?
I can keep the compiler happy by defining Value as "protected T? Value" but that adds unnecessary complication elsewhere to check for a null value when I know darn well that inside BoolDataNode that Value will never be null.
The right thing to do is to make this a protected T? Value field, since if T is a reference type, you'll be assigning null. People accessing your Value field need to know that if T is a non-nullable reference type, they might still be getting a null out.
You're confused about the meaning of T? when T is unconstrained however. T? means that the value is "defaultable", not "nullable". That's a subtle difference, but means that you can assign a value of default(T). Another way of putting that is:
If T is a reference type, T? means that you can assign null. If T is a value type, the ? in T? effectively has no meaning.
In other words, DataNode<string>.Value is of type string?, but DataNode<bool>.Value is of type bool, not bool?.
(Technically, there's no way to have T?, when T is unconstrained and is a value type, mean Nullable<T>. For nullable value types, the compiler outputs a member of type Nullable<T> rather than T. However, generics are expanded by the runtime rather than the compiler.)
Note that this changes if T is constrained to be a value type: in that case, T? suddenly starts meaning Nullable<T>.

When would I use "NotNullIfNotNull" on a property referencing itself?

In class Microsoft.Net.Http.Headers.ContentRangeHeaderValue, there is a nullable value type property (long?) that is decorated with a NotNullIfNotNull attribute referencing itself (property Length).
[NotNullIfNotNull(nameof(Length))]
public long? Length { get; private set; }
What is the purpose of this attribute in the context of a value type and what is the difference to simply omitting the attribute declaration?
According to the definition: A return value, property, or argument isn't null if the argument for the specified parameter isn't null.
The use-case scenario:
Sometimes the null state of a return value depends on the null state of one or more arguments. These methods will return a non-null value whenever certain arguments aren't null. To correctly annotate these methods, you use the NotNullIfNotNull attribute.
Examples or code snippets can be found here.
I think I slowly get an idea what problem this declaration attempts to solve:
The property could write the value it receives to a different variable than the one that is returned (using a property like this)
[NotNullIfNotNull(nameof(Length))]
public long? Length {
get { return _length }
private set { _anotherLength = value }
}
or simply ignore the value in the setter or do some other strange things, the attribute is needed to tell the analyzer the value given to the setter does indeed set the variable returned in the getter.

String is Nullable returns false

Why does:
string s = "";
bool sCanBeNull = (s is Nullable);
s = null;
sCanBeNull equate to false?
I'm writing a code generator and need to ensure every type passed to it is nullable, if it isn't already.
//Get the underlying type:
var type = field.FieldValueType;
//Now make sure type is nullable:
if (type.IsValueType)
{
var nullableType = typeof (Nullable<>).MakeGenericType(type);
return nullableType.FullName;
}
else
{
return type.FullName;
}
Do I need to have to explicitly check for a string or am I missing something?
is tells you whether a value is of a particular type, or one derived from that particular type.
Nullable is a generic struct that allows for nullable versions of non-nullable values.
string is not a Nullable
To tell if a type can have null values use the fact that for all such types the default value is null, while for all other types it is not:
default(string) == null; // true
string is a reference type so it is not Nullable as that is reserved for value types.
In fact:
var nullable = new Nullable<string>();
Gives a compile time error.
The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Nullable'
The rational behind System.Nullable is to be able to represent undefined Value Types using the null keyword. It does not mean that you can check whether some variable can be set to null using someVar is Nullable.
If at compile-time you cannot know beforehand whether some variable would be a value-type or a reference-type, you can use:
!someVar.GetType().IsValueType
But usually a generic argument would be a better approach.
Nullable is just a normal class like MyClass or System.String (Nullable<T> is struct though).
So if you type:
class _Nullable {}
struct _Nullable<T> {}
class Program
{
static void Main()
{
string a = "";
Console.Write(a is _Nullable);
}
}
You wouldn't be surprised if it returns false right ?
If you want to check if something is nullable or not you can use if(!(a is ValueType))
string a = "";
Console.Write("a is nullable = {0}", !(a is ValueType));
Output : a is nullable = true

Reflection - check all nullable properties have values

I have to loop through all the properties in a few classes and check any nullable properties to see if they have a value. How do I cast the value returned from propertyInfo.GetValue() to a generic nullable type so that I can check the HasValue property?
Code snipped for brevity:
foreach (PropertyInfo propInfo in this.GetType().GetProperties())
{
if (<Snip: Check to see that this is a nullable type>)
{
//How do i cast this properly in here to allow me to do:
if(!((Nullable)propInfo.GetValue(this, null)).HasValue)
//More code here
}
}
note I'm assuming you mean Nullable<T>; if you mean Nullable<T> or a reference, then you already have it: object (from GetValue) - just check for null.
In the case of Nullable<T>; you can't cast to a single non-generic type (other than object) - but you don't need to; just check that it isn't null, since empty Nullable<T> is boxed to null, and GetValue returns object (hence it boxes the value).
if(Nullable.GetUnderlyingType(propInfo.PropertyType) != null) {
// it is a Nullable<T> for some T
if(propInfo.GetValue(this, null) != null) {
// it has a value (it isn't an empty Nullable<T>)
}
}
To clarify, Nullable is a static utility class that is completely separate to the Nullable<T> struct; so you don't cast to Nullable at all. As it happens, Nullable exists to provide things like the GetUnderlyingType that helps you work with Nullable<T>.
Since you've established that the property is of type Nullable<something>, you know its value has a HasValue property - so find that property by reflection and get its value.

Categories

Resources