-
Notifications
You must be signed in to change notification settings - Fork 10.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[C#] Add nullable type attributes to Grpc.Core.Api #27887
Conversation
@@ -64,21 +64,21 @@ internal struct AsyncCallState | |||
internal Task<Metadata> ResponseHeadersAsync() | |||
{ | |||
var withState = responseHeadersAsync as Func<object, Task<Metadata>>; | |||
return withState != null ? withState(callbackState) | |||
return withState != null ? withState(callbackState!) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return withState != null ? withState(callbackState!) | |
return withState != null && callbackState != null ? withState(callbackState) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If withState is not null then callbackState has to also be not null. I chose not to use a Debug.Assert because this library targets netstandard2.0 and Debug.Assert isn't annotated there to correctly suppress the nullable warning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense. It would be neat if we could use MemberNotNullWhen but I'm not sure if it can be used in private members.
@@ -43,7 +43,7 @@ public InterceptingCallInvoker(CallInvoker invoker, Interceptor interceptor) | |||
/// <summary> | |||
/// Intercepts a simple blocking call with the registered interceptor. | |||
/// </summary> | |||
public override TResponse BlockingUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request) | |||
public override TResponse BlockingUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string? host, CallOptions options, TRequest request) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we allowing a null host in all these APIs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generated code passes in null -
grpc/src/csharp/Grpc.Examples/MathGrpc.cs
Line 224 in 6d28740
return CallInvoker.BlockingUnaryCall(__Method_Div, null, options, request); |
There is also some Grpc.Core.Api code that passes down this code path, but I don't recall exactly where it is to link to it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
host == null
means "use the default host / authority". You can set "host" explicitly if you want to use multiple virtual hosts on a single host.
See "Authority" in https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md
So setting host=null
is actually the most common use case.
I will look at this in detail once I successfully upgrade the dotnet SDK in the grpc/grpc repo: #27966 (it's proving difficult). |
SDK has been updated in #27966, you can rebase now. |
ae5aa65
to
464c4e6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM once the changes from #27886 are separated from this PR.
Just to double check please confirm that this feature is 100% backward compatible with older runtimes / codebases. Specifically:
- the public API will stay binary compatible with older releases (IMHO that's because the internally, the
?
and!
operators only add attributes to the the existing types (which stay unchanged) - unless the nullable context is explicitly set by the user in their project, the behavior of all their existing code will stay the same. (as by default the nullable checks are disabled).
@@ -43,7 +43,7 @@ public InterceptingCallInvoker(CallInvoker invoker, Interceptor interceptor) | |||
/// <summary> | |||
/// Intercepts a simple blocking call with the registered interceptor. | |||
/// </summary> | |||
public override TResponse BlockingUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request) | |||
public override TResponse BlockingUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string? host, CallOptions options, TRequest request) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
host == null
means "use the default host / authority". You can set "host" explicitly if you want to use multiple virtual hosts on a single host.
See "Authority" in https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md
So setting host=null
is actually the most common use case.
464c4e6
to
04979b9
Compare
Done
Yes
Yes, it is off by default. FYI there is a chance that someone who has already enabled nullable warnings in an app could get new warnings after this assembly is annotated. That's pretty normal as more libraries are annotated, and it is only compile time warnings. There is no change at runtime. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
@apolcyn can you please add another LGTM.
https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references
@jtattermusch @captainsafia