-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Enforce non-null factory return in Lazy<T> #111987
Comments
It would definitely be a breaking change. It's valid to have a |
In other words, the |
As @stephentoub and @huoyaoyuan said, it's not really actionable. It's unfortunate, but it's a fact of life when dealing with nullable reference types. As you showed, there's already nothing stopping someone from returning public static void BlowUp()
{
string result = GetString();
Console.WriteLine(result.Length);
return;
// assume this method is in an external assembly, so you
// don't actually know it returns null without inspection
static string GetString() =>
null!;
} The "simplest" way to solve this would be the runtime providing some |
That would do what? |
People could use it to throw if a var landmine = new Lazy<object>(createLandmine);
InvalidOperationException.ThrowIfNull(landmine); // <--
Console.WriteLine(landmine.Value.ToString()); Essentially, the same as |
Tagging subscribers to this area: @dotnet/area-system-runtime |
Note that this behavior is covered under https://learn.microsoft.com/en-us/dotnet/csharp/nullable-references#nullable-context The code compiled under the segment that is The fix for this is to ensure that all code is nullable enabled so that user-expectations can be met. |
This issue has been marked |
In C#, the contract of non-nullability for
Func<T>
can be easily violated without any compiler error or warning, even in legitimate code, specially when crossing assembly boundaries:Even though the factory implementation can be provided via public interface, the class
Lazy<T>
trusts it blindly:https://github.com/dotnet/runtime/blob/release/8.0/src/libraries/System.Private.CoreLib/src/System/Lazy.cs#L323C1-L324C1
https://github.com/dotnet/runtime/blob/release/8.0/src/libraries/System.Private.CoreLib/src/System/Lazy.cs#L378C1-L379C1
I would argue that, at the boundary of a System project and a non-System project, the nullability contract should be enforced at runtime, by the System project, for incoming data: (compare this statement to rule CA1062)
https://github.com/dotnet/runtime/blob/7693b6d0202281dc38dcfb9562e9064fcd13bc61/src/libraries/System.Private.CoreLib/src/System/Threading/LazyInitializer.cs#L114C1-L115C1
On the other hand, a non-System project should be able to trust the type signature of a concrete object implemented in the System project:
Whether this would be a breaking change is debatable.
The text was updated successfully, but these errors were encountered: