Skip to content

Conversation

@piksel
Copy link
Member

@piksel piksel commented Aug 6, 2020

Adds explicit null checking for reference types using C# 8.

Running InferNull on the main source project made it go down from 661 warnings to 214.
After some cleaning and refactoring, the project now happily compiles without any warnings and with almost complete null-checking (some places were just explicitly ignored since they would have a much greater performance impact).

I certify that I own, and have sufficient rights to contribute, all source code and related material intended to be compiled or integrated with the source code for the SharpZipLib open source product (the "Contribution"). My Contribution is licensed under the MIT License.

@Numpsy
Copy link
Contributor

Numpsy commented Aug 6, 2020

With regards to the EmptyRefs thing:

When looking at the FxCop/analyzer warning stuff I saw multiple suggestions to replace allocations of [0] length arrays with Array.Empty<>.
Didn't try to do anything with it yet due to the lack of Array.Empty in NET45, but it did cross my mind to see if it was worth/possible to add an internal definition of Array.Empty in that version, and then just use Array.Empty in the rest of the code, which wouldn't have to be different on different targets then?

@piksel
Copy link
Member Author

piksel commented Aug 6, 2020

[...] add an internal definition of Array.Empty in that version, and then just use Array.Empty in the rest of the code, which wouldn't have to be different on different targets then?

Since Array is defined in System I just disregarded that idea, but now that you mention it, it could be added as an extension method and then keeping the actual instances in the static class.

@Numpsy
Copy link
Contributor

Numpsy commented Aug 6, 2020

I thought i'd seen some other project do that, but maybe i'm misremembering, though the implementation is apparently only something like

internal static class EmptyArray<T>
{
	public static readonly T[] Value = new T[0];
}

anyway.

/// <param name="isStreamOwner">Both streams are closed on completion if true.</param>
/// <exception cref="ArgumentNullException">Input or output stream is null</exception>
public static void Decompress(Stream inStream, Stream outStream, bool isStreamOwner)
public static void Decompress(Stream? inStream, Stream? outStream, bool isStreamOwner)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should these streams be nullable if the function throws on null?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure, I don't think we can check for null if we say that they're non-nullable. I have to read up on how to interface with consumer code with and without Nullable enabled.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Callers without Nullable enabled will just behave as they do before (i.e treat it as though it can be null), and you can still check for null and throw for those cases (or in general really, given that the checks don't actually prevent it from being null even if marked as non-nullable).

FxCop still gives warnings that non-nullable parameters to public functions should be checked before use as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep you're right. There are some instances where you branch on null that the compiler thinks it should be nullable.

@piksel
Copy link
Member Author

piksel commented Aug 6, 2020

[...] though the implementation is apparently only something like

Yeah, that is both the implementation in mscorlib and the way I polyfilled it now. I haven't pushed those changes yet though, since I'm not happy with the naming yet.

@Numpsy
Copy link
Contributor

Numpsy commented Dec 6, 2020

Would it be worth breaking the Array.Empty bits out into a seperate change? (it could pass as a trivial optimization, and shou;dn't rely on the other nullability changes?)

piksel pushed a commit that referenced this pull request Mar 7, 2021
* Add the 'EmptyRefs' helper, to support Array.Empty on .NET 4.5 (ref: #501)
* Replace uses of 'new T[0]' with 'Empty.Array<T>'
@piksel
Copy link
Member Author

piksel commented May 8, 2021

Closing this as it would have to be redone now anyway.

@piksel piksel closed this May 8, 2021
@piksel piksel deleted the nullable branch July 5, 2021 11:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants