How to avoid null params with nullable reference types - c#

Since C# 8.0 nullable reference types are possible. If they are enabled you have to append the ? to the reference type to make it nullable.
My question now is how can I force a method parameter that uses the params keyword, to be not-nullable.
Example:
#nullable enable
public void MyMethod(params int[] foo)
{
// foo can still be null
// How can I ensure that foo is not null at compile-time
}
MyMethod(null); // valid, but why?
Another question which is similar, would be: Why is params int[] foo even nullable in the first place? I would expect something like params int[]? foo to make it nullable. But with params this seems to be different.
I tried NotNullAttribute but this only gives a warning. I want to disallow that completely by the compiler.
Does anybody know a way to make it non-nullable and maybe can tell me why params allows nullable even with #nullable enable?

valid, but why?
Parameter arrays where introduced before the nullable reference types and from the documentation it is valid to pass null as a value for such parameter:
A caller can then invoke the method in either of four ways:
By passing an array of the appropriate type that contains the desired number of elements.
By passing a comma-separated list of individual arguments of the appropriate type to the method.
By passing null.
By not providing an argument to the parameter array.
Does anybody know a way to make it non-nullable and maybe can tell me why params allows nullable even with #nullable enable?
If the call is made inside nullable enabled context compiler
should issue a warning. You can change this warning into by changing compiler settings. See this question.

this will be valid too
MyMethod();
it has nothing to do with nullables. You use nullable a wrong way here. It is because you are using the params keyword.
From MSDN
"Using the params keyword, you can specify a method parameter that takes a variable number of arguments. The parameter type must be a single-dimensional array.
When you call a method with a params parameter, you can pass in:
....
No arguments. If you send no arguments, the length of the params list is zero. "
When you pass null, you are assigning null to arguments explicitly.
but if you want to use nullable and compiler wornings, make your code like this
#nullable enable
public void MyAnotherMethod()
{
MyMethod(null); // Compiller will issue a warning
MyMethod(); // No warning
}

Referencing to the MSDN concerning Nullable reference types
Known pitfalls
Arrays and structs that contain reference types are known pitfalls in nullable references and the static analysis that
determines null safety. In both situations, a non-nullable reference
may be initialized to null, without generating warnings.
So you can't make these types non-nullable because params is based on array.
Possible solution is to create your own non-nullable type or pass existing (which implements IEnumerable, for example). I think you should reach the same effect as with params.

Related

Nullable reference types on object array

I've a .NET 6 project with non-nullable reference types.
I want to constrain the objects parameter to a non-nullable array of nullable objects.
I've 4 possible methods and assume one of these should work.
public void Method1(object[] objects)
public void Method2(object[]? objects)
public void Method3(object?[] objects)
public void Method4(object?[]? objects)
Method2 and 4 both accept a null. So I'm left with 1 and 3 but I get a warning on both:
CS8625 Cannot convert null literal to non-nullable reference type
I would expect method3 to work without warning:
Method3(new object[] { null });
Is there any way to get this done?
My question is answered in one of the comments. I should of course have used:
Method3(new object?[] { null });
This answer is just for completeness, so that the answer is not only in the comments
The problem is not with the declaration of your method and it's parameters, but instead with the call. You are creating an array of non-nullable objects and initializing it with one null. You should instead create an array of nullable objects like this: new object?[] { null }
To answer your confusion with the method declarations:
The nullability operator always referes to the previous type.
So in object[]? the nullability operator applies only to the array. This means that null and an array of non-nullable objects would fit this type.
When you write object?[], the nullability operator applies only to object. This means that a non-nullable array of nullable objects matches this type.

What is the signature of a method with params?

I was about to bind Expression.Lambda programmatically (because of unknown/variable type parameters), and found out that if the target method uses params, the reflected calling is a bit different than calling directly.
First, in the official documentation, the "signature" (although this is more like a XML-doc):
public static
System.Linq.Expressions.Expression<TDelegate>
Lambda<TDelegate>(
System.Linq.Expressions.Expression body,
params System.Linq.Expressions.ParameterExpression[]? parameters
);
Notice that it the 2nd param is marked as optional, and we can write Expression.Lambda<T>(...). If in Visual Studio, you go to the disassembled declaration list, you can see this:
public static
Expression<TDelegate>
Lambda<TDelegate>(
Expression body,
params ParameterExpression[] parameters
);
2nd parameter is no longer marked as option. Now when I tried to invoke this method using reflection as:
var lambdaFactory = typeof(Expression)
.GetMethods()
// Filter overloads
.Single(x => x.ToString() == "System.Linq.Expressions.Expression`1[TDelegate] Lambda[TDelegate](System.Linq.Expressions.Expression, System.Linq.Expressions.ParameterExpression[])")
.MakeGenericMethod(myTypeArgument);
var lambda = (LambdaExpression) lambdaFactory.Invoke(
null,
new object[] {
...
// ,null
}
);
, I got TargetParameterCountException: Parameter count mismatch.. But if null is added as another parameter, it works perfectly.
This is a bit strange for me. Why does the MS Docs use ? (optional marker)? Is the params argument really optional similarly to regualr option arguments, like string Foo(int a = 1); var result = Foo();? Or it is just a syntactic sugar? So that's why I may call directly Expression.Lambda<T>(...) in the editor, but the compiled code can be different (which is compatible with the reflection system too). If so, does that mean the method always receives the null value, even if I don't specify values? But if a method uses params argument, and nothing is passed, the argument from the method body is a valid array with .Count == 0, not null. Is it safe to pass null using reflection, or I should create an empty object array?
The ? in the docs denote a nullable reference type, not an optional parameter. Nullable reference types are purely a "compile-time check" thing, and at runtime, they are no different from regular old reference types.:
Nullable reference types aren't new class types, but rather annotations on existing reference types. The compiler uses those annotations to help you find potential null reference errors in your code. There's no runtime difference between a non-nullable reference type and a nullable reference type. The compiler doesn't add any runtime checking for non-nullable reference types. The benefits are in the compile-time analysis. The compiler generates warnings that help you find and fix potential null errors in your code. You declare your intent, and the compiler warns you when your code violates that intent.
This explains why the ? disappears when you look at the "disassembled declaration list".
All ? tells you is that you can pass null to this parameter and the method will still work.
In this case, an alternative to passing null is to pass an empty array of ParameterExpressions:
var lambda = (LambdaExpression) lambdaFactory.Invoke(
null,
new object[] {
someBodyExpression,
new ParameterExpression[] { }
}
);
This would reflect how you call Lambda non-reflectively:
// I'm passing no extra arguments, so an empty array is passed to the "params" parameter
Lambda<T>(someBodyExpression)

When should one use nullable types in c#?

I have been repeatedly asked the following questions in many interviews.... But still can't explain them with a simple example...
What are nullable types in c#?
When should one use nullable types in c#?
Can you give a simple example?
Any suggestions?
From Using Nullable Types (C# Programming Guide) (Link updated circa 2018)
For an example of when you might use a
nullable type, consider how an
ordinary Boolean variable can have two
values: true and false. There is no
value that signifies "undefined". In
many programming applications, most
notably database interactions,
variables can exist in an undefined
state. For example, a field in a
database may contain the values true
or false, but it may also contain no
value at all. Similarly, reference
types can be set to null to indicate
that they are not initialized.
Null means "no value" or "no data". You use nullable types when "no value" is a valid value in the context of whatever system you are desining/using.
int? weightOfCargo = TryGetTruckCargoWeight()
In this case, the nullable type indicates that TryGetTruckCargoWeight() may return null. The meaning of this would genereally be that the data is unavailable (maybe there's no truck, maybe it hasn't been weighed, etc).
Consider following example:
A tool has settings specified via the UI. However, the tool can also be run from the command-line and the settings specified in the UI can be overridden via the commandline. So the code is as follows :
bool? setting1;
...Process command line, if setting specified do:
setting1.Value = setting;
...later
if(setting1.HasValue)
ui.setting1 = setting1.Value
Whenever you are using designated values to represent a null value:
* A DateTime minimumvalue to represent a value of nothing
* -1 to represent an unset value for an integer
then a nullable type would be a better choice.
AS we all know there are two different types in C#
•Refrence type
•Value type
Reference type can be represent as non existent value (NULL) but Vaue type , however cannot represent NULL value.
For e.g
Since String is reference type you can declare it as null
String s=null; //ok
But if you try to declare value type such as Int32 to null it produceses compiler error
Int32 i=null; // compiler error
To represent null in a value type, you must use a special construct called a nullable type. It is represented using ? symbol.
Int32? I=null; //now its ok
Now scenario when nullable types commanly used is in database programming where calss is map to table with nullable columns.
• If the columns are reference type that is String such as (email address and customer address), there is not a problem as you can defined it as null in C#
• But if the columns are value type that is double such as (customer account balance), you cannot map it to C# without using nullable types.
For e.g
// maps to a Customer table in a database
public class Customer
{
...
public decimal? AccountBalance;
}
One more example:
imagine, you need to create a GetArticles method in your BLL. This method should take such arguments as date period (from and to arguments), search string (search argument) and document category (categoryId argument). All these arguments are optional. So in one case you want to define only from and search argument, in other only categoryId argument.
To do this you may create a lot of overloads for GetArticles method with necessary arguments combination. The other way is to define the only one method GetArticles(DateTime? from, DateTime? to, string search, int? categoryId) for this. In this case if argument is null it will be skipped.
Of cause I know about a new feature in .NET 4.0 called optional parameters and named arguments but before this it was a nice workaround for me.
C# has two type of data types. Value type and reference types. String is reference type and int is value type. A reference type can be assigned with a null value like string s = null;. But you can not assign a null value directly to a integer. Like int a = null // So to make the value type accept a null value, nullable types are used. To make it nullable, a ? is added in
int? a = null;//ok.
// to replace
// if(foo.Id > 0)
if(foo.Id.HasValue)
{
Update(foo);
}
else
{
Insert(foo);
}
I think if we talk about real world scenario when your Database table contains nullable columns in it and you need to create DTOs(Data Transfer Objects) as Db Entity mapping. In such scenarios you need to get exact same datatype mapping in you Entity classes, To achieve such requirement nullable types are really very useful to create exactly same mapping and allow user to easily work in this senario.
Regards.
Nullable types are used to hold variables whose values are null at runtime. Its important because some table fields during insert operations are not initially determined. Nullable types come in handy here.

Nullable List<> as out parameter

Is this possible?
private void Test(out List<ExampleClass>? ExClass)
{
}
A nullable List<> that is also an out parameter?
List<T> is a reference type (class), so no ? is required. Just assign null to ExClass parameter in method body.
As Anton said, you don't need to use Nullable<T> - but it could certainly be an out parameter:
private void Test(out List<ExampleClass> foo)
It's possible you're confusing a nullable List<T> with a List<T?> which would be valid for value types... for example, you could use:
private void Test(out List<Guid?> foo)
which would be an out parameter which is a list of nullable guids.
On the other hand, it's not generally nice to have out parameters in void methods - you should usually use it as the return type instead.
Use ? just for nullable ValueTypes.
Being an out parameter or not is irrelevant here. But you cannot make a Nullable<T> with a class; T must be a struct. Otherwise the compiler will complain.
In addition to this, it is considered bad style to capitalise the name of a parameter (use exClass instead of ExClass). Your programs will work the same, but anybody reading your code might be misled.

Do C# Nullable variables still function as value types?

If I declare a nullable (either via Nullable or the ? symbol) variable from a value type, does it still respect the rules of value types (i.e. pass by value by default, deallocated when it falls out of scope, not when the garbage collector runs) or does it turn into a reference type since it's actually of type Nullable?
The documentation is here:
http://msdn.microsoft.com/en-us/library/b3h38hb0.aspx
As you can see, the documentation describes this as the "nullable structure", indicating that it is a value type. Also, the documentation gives the first lines of the declaration of the type:
public struct Nullable<T> where T : struct, new()
again showing that the type is a value type.
Yes, System.Nullable is a generic Struct, ie value type.
Nullable value types are essentially just a struct wrapper around a value type which allows them to be flagged as null.
something like this:
struct Nullable<T>
{
public T Value;
public bool HasValue;
}
I believe it's actually more complex than that under the hood, and the compiler does lots of nice stuff for you so you can write for example if(myInt == null). But yes, they are still value types.

Categories