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.
Related
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>.
I have a fluent validator:
RuleFor(x => x.TypeTest)
.NotEmpty()
.WithMessage(x => string.Format(MessagesValidation.ValeurRequise, nameof(x.TypeTest)))
TypeTest is enum type
public enum TypeTest
{
A,
B,
C,
}
Even I give TypeTest = "A" validator doesn't valid it and return an error.
Solution but I didnt Like it:
public enum TypeTest
{
Empty = 0,
A,
B,
C,
}
is there any other solution ? please.
Updated
the problem is anytime I give the first value, it consider as Empty, and validator return an error. that is why I add a new value as Empty but im asking if there's an other way ?
Why are you trying to validate an enum type using NotEmpty() method? Enum can never be empty. It always has a default value.
If you want to validate value of an enum type, you should use IsInEnum() method.
Also, you can't assign a string to an enum type as you've written in your question.
If you want TypeTest to allow for "empty" values, make the property nullable:
public TypeTest? TypeTest { get; set; }
// ^ (the question mark after the type allows nulls to be assigned)
That should get the "NotEmpty()" validator working, but the downside is introducing an additional possible value for an enum: null. Depending on your use case, a null value might be desirable. Changing the type of the property from TypeTest to TypeTest? will require downstream code changes. Anything relying on the TypeTest property will need to access the enum value using x.TypeTest.Value rather than just x.TypeTest.
In my current project, i have a Value<T> class.
Currently T can be anything, but we must support Null values, so currently we use it in two forms:
Value<string> or Value<int?>
Can I in any way create a Value class that would allow me to specify Value<string> or Value<int>, but where the effect is that Value holds T for classes, but holds T? for structs?
The goal is to avoid the case where a developer specifies Value<int> and we later have problems, because we dont handle Null values properly.
Ie, id like Compiler suport for avoiding errors.
Can I in any way create a Value class that would allow me to specify Value<string> or Value<int>, but where the effect is that Value holds T for classes, but holds T? for structs?
No, because you cannot have "or" logic in generic type constraints.
To achieve "or" logic in generic type constraints, you would have to create two separate generic classes, each with their own generic type constraint. Note that these two classes could inherit from a shared generic base class which has no type constraint at all.
If that base type is abstract, then you can be sure that consumers must have passed one of the derived classes' type constraint check (assuming no one added some other derived classes)
It would be more appropriate to change your expectation instead of trying to make it the way you currently want to.
but we must support null values
If instead of null, you use default(T), then the problem is resolved.
For class types, default(MyClass) effectively resolves to null
For structs, default(MyStruct) returns a struct whose properties all contain their default values
default(MyStruct) is the common way to use the concept of "nullability" without having to use a literal null value.
A usage example:
public class Container<T>
{
private readonly Random _random = new Random();
public T DoSomething(T input)
{
//always returns "nothing"
return default(T);
}
}
public class MyClass
{
public int Value { get; set; }
}
public struct MyStruct
{
public int Value { get; set; }
}
public class Test
{
public bool ContainerReturnsNothing<T>(T input)
{
var container = new Container<T>();
var output = container.DoSomething(input);
return output.Equals(default(T));
}
public void TestAClassAndAStruct()
{
ContainerReturnsNothing(new MyClass() {Value = 1}); // true
ContainerReturnsNothing(new MyStruct() {Value = 1}); // true
}
}
In the TestAClassAndAStruct method you can see that this generic call stack works exactly the same regardless of whether you use a class or a struct.
If you change the container to return input; then ContainerReturnsNothing will return false in both cases.
One thing you may need to be aware of is that a "nothing" struct cannot be differentiated from a struct that was created but whose properties all happen to have default values. If a struct whose properties all happen to have default values, is a meaningful (i.e. not-nothing) struct value in your case, then this is an issue.
A simple example here is int, whose default(int) resolves to 0. If 0 is a meaningful value, then it is therefore not nothing, which means that you cannot use 0 to represent nothingness.
But you can work around that issue by adding a property which is forced to contain a non-default value when a constructor is executed:
public struct MyStruct
{
public bool IsConstructed { get; } // default false
public int Value { get; }
public MyStruct(int myValue)
{
this.IsConstructed = true;
this.Value = myValue;
}
}
default(MyStruct) will always have IsConstructed set to false.
Every instantiated struct will always have IsConstructed set to true.
This avoid the issue since they will never be equal to one another. In other words:
var myStruct = new MyStruct(0);
var isNull = myStruct.Equals(default(MyStruct));
isNull is false because myStruct and default(MyStruct) contain a different value for IsConstructed (true and false, respectively).
If you run this same check using the MyStruct class from the original example, isNull would be true because all the properties match, i.e. myStruct and default(MyStruct) both have a Value property set to 0.
I'm currently rewriting parts of a custom RPC mechanism (which cannot be replaced by something else, so don't suggest that ;-) ). The arguments of a call are collected in a custom collection that uses a dictionary internally. There is a method T Get<T>(string) to retrieve a named argument. For optional arguments, I wanted to add a TryGet<T>(string) method that returns the argument or null if it doesn't exist, so that the calling code can provide a default value using the null coalescing operator. Of course, for a value type this doesn't work, but I could use T? instead, which is what I want.
So what I have is this:
public class Arguments
{
// lots of other code here
public T TryGet<T>(string argumentName) where T : class
{
// look up and return value or null if not found
}
public T? TryGet<T>(string argumentName) where T : struct
{
// look up and return value or null if not found
}
}
With that, I'd like to be able to do the following:
return new SomeObject(
args.TryGet<string>("Name") ?? "NoName",
args.TryGet<int>("Index") ?? 1
);
Since the constraints are mutually exclusive, the compiler should be able to produce the correct code (it's always possible to infer the call from the generic type given at the call site). The compiler complains that the type already defines a member called "TryGet" with the same parameter types.
Is there any way to make something like this work without giving the two methods different names?
Constraints are not part of the signature. thus the answer to your question is no.
The way classes in the .NET Framework handle this scenario is TryGetValue with an out parameter. The return value is an indicator of whether the get was successful, where the out parameter contains the value requested (on success) or a suitable default value (on failure).
This pattern makes the implementation very simple for reference and value types. You would only need a single method to handle both scenarios.
For an example of this pattern, see Dictionary<TKey,TValue>.TryGetValue.
The reason this doesn't work is because you cannot have two methods with the same name and same argument types (the return type is not taken into account for method overloading). Instead you could define a single method without the generic constraint which will work for both value and reference types:
public T TryGet<T>(string argumentName)
{
if (!_internalDictionary.ContainsKey(argumentName))
{
return default(T);
}
return (T)_internalDictionary[argumentName];
}
An alternative solution could be this one:
public class Arguments {
public T Get<T>(string argumentName,T defaultValue) {
// look up and return value or defaultValue if not found
}
}
return new SomeObject(
args.Get<string>("Name","NoName"),
args.Get<int>("Index",1)
);
In that particular case you would not even have to specify the generic type, as it could be inferred by the default parameter:
return new SomeObject(
args.Get("Name","NoName"),
args.Get("Index",1)
);
Although it does not work directly due to identical argument types, You can do that by adding optional defaultValue parameter which defaults to null:
public class Arguments
{
// lots of other code here
public T? TryGet<T>(string argumentName, T? defaultValue = null) where T : class
{
// look up and return value or null if not found
}
public T? TryGet<T>(string argumentName, T? defaultValue = null) where T : struct
{
// look up and return value or null if not found
}
}
The reason this one works is that second argument type is different for both contraints (In the the method with class constraint it is simply T, and in the method with struct constraint it is Nullbale<T>).
Following code works as you would expect:
var args = new Arguments();
var stringValue = args.TryGet<string>("Name") ?? "NoName";
var intValue = args.TryGet<int>("Index") ?? 1;
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.