Skip null-element check for collections with a value-type element type#5432
Skip null-element check for collections with a value-type element type#5432adityapatwardhan merged 7 commits intoPowerShell:masterfrom
Conversation
build.psm1
Outdated
| $ReleaseVersion = $ReleaseTagToUse | ||
| } else { | ||
| $ReleaseVersion = (Get-PSCommitId) -replace '^v' | ||
| $ReleaseVersion = (Get-PSCommitId -WarningAction SilentlyContinue) -replace '^v' |
There was a problem hiding this comment.
This change does not seem related to this PR.
There was a problem hiding this comment.
Yes, I will revert it.
| $expected = $baseline + 20 | ||
|
|
||
| if ($IsWindows) { | ||
| $null = New-Item -Path $TESTDRIVE/file1 -ItemType File |
There was a problem hiding this comment.
-ItemType File is not necessary anymore. The default itemtype is file
There was a problem hiding this comment.
OK. I will remove it.
| param( | ||
| [ValidateNotNullOrEmpty()] | ||
| $Value, | ||
| [string] $TestType |
There was a problem hiding this comment.
Can you add a parameter like: [System.Nullable``1[[System.Int32]]] $nullableInt
There was a problem hiding this comment.
A [System.Nullable[int]] parameter is not useful in this case because the type is not a collection. Hence ValidateNotNullOrEmpty attribute won't validate it as a collection.
| isEmpty = false; | ||
| // If the element of the collection is of value type, then no need to check for null | ||
| // because a value-type value cannot be null. | ||
| if (isElementValueType) { break; } |
There was a problem hiding this comment.
It seems we can move this before while line 1997 - we check first element in ParameterCollectionTypeInformation in IsArgumentCollection.
There was a problem hiding this comment.
We don't check the elements of arguments in IsArgumentCollection. The argument passed in is the type of arguments, not arguments itself.
There was a problem hiding this comment.
Yes, I see that no element check is in ParameterCollectionTypeInformation.
But the code is not clear. Maybe:
# Check if the collection is empty.
if (ienum.MoveNext()) isEmpty = false;
# Check every element in the collection only if the element type of the collection is NOT a value type.
if (!isElementValueType && !isEmpty)
{
do
{
...
object element = ienum.Current;
...
} while(ienum.MoveNext()))
}There was a problem hiding this comment.
I think the logic is clear -- if the element type of the collection is a value type, then skip checking each element. The isEmpty check is needed in either case.
There was a problem hiding this comment.
The logic is right but the code is slightly tricky for me. I added your comments in my sample above. Also we do two actions that can be carried before the cycle - if we are thinking about performance it is important - I think Measure-Object show a delay starting with 10000 elements.
There was a problem hiding this comment.
I get your point. I will update as you suggested. Thanks!
| } | ||
| } | ||
| else if ((ienum = arguments as IEnumerable) != null) | ||
| else if (IsArgumentCollection(arguments.GetType(), out bool isElementValueType)) |
There was a problem hiding this comment.
Is in the context isEmpty = !isElementValueType ?
There was a problem hiding this comment.
No, the check of element type doesn't involve inspecting the elements of the collection. You can see that the type of arguments is passed in instead of the arguments itself.
Please see the constructor of ParameterCollectionTypeInformation for details.
| isEmpty = false; | ||
| // If the element of the collection is of value type, then no need to check for null | ||
| // because a value-type value cannot be null. | ||
| if (isElementValueType) { break; } |
There was a problem hiding this comment.
Why if we calculate this before the cycle?
There was a problem hiding this comment.
Same reason as above. The element type is resolved using the collection type.
|
@iSazonov You comments have been addressed. Please take another look when you have time. Thanks! |
iSazonov
left a comment
There was a problem hiding this comment.
LGTM with two minor comments.
| Context "ValidateNotNull, ValidateNotNullOrEmpty and Not-Null-Or-Empty check for Mandatory parameter" { | ||
|
|
||
| BeforeAll { | ||
| function MandType { |
There was a problem hiding this comment.
Could you please use more nice name? MandatoryType?
| #region NULL validation attributes | ||
|
|
||
| /// <summary> | ||
| /// Base type of Null Validation attributes |
There was a problem hiding this comment.
Could you please add final dot in public comments?
|
@PowerShell/powershell-committee reviewed this and approves with this change |
|
@daxian-dbw restarted AppVeyor build. Failed due to #5567 |
PowerShell#5432) * Fix NotNullOrEmpty check logic * Fix a test issue on Unix
#5432) * Fix NotNullOrEmpty check logic * Fix a test issue on Unix
Fix #5417
Mandatoryparameter,ValidateNotNullandValidateNotNullOrEmptyattributes, skip null-element check if the collection's element type is value type.ValidateNotNullandValidateNotNullOrEmpty, they are changed to do null/empty check only on collections (as defined inParameterCollectionTypeInformation) and hashtable. They currently enumerate elements of any object that implementsIEnumerableand also enumerate elements if the argument is an enumerator. I think this behavior is not right for the following reasons:ValidateNotNull/ValidateNotNullOrEmptyattributes wait on that.GetEnumerator()method is not supported in .NET Core on COM object. (See the COM example below)COM Example
Enumerator Example