From 5beb737d437a3ffc47b12b2d10855f34a4757247 Mon Sep 17 00:00:00 2001 From: Shad Storhaug Date: Fri, 23 Apr 2021 17:01:21 +0700 Subject: [PATCH] Updated NullPointerException with static factory methods and added documentation to explain how to convert (see #446). --- .../RuntimeExceptions/NullPointerException.cs | 65 ++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/src/Lucene.Net/Support/ExceptionHandling/Exceptions/RuntimeExceptions/NullPointerException.cs b/src/Lucene.Net/Support/ExceptionHandling/Exceptions/RuntimeExceptions/NullPointerException.cs index 249c2dfce4..955d0b8197 100644 --- a/src/Lucene.Net/Support/ExceptionHandling/Exceptions/RuntimeExceptions/NullPointerException.cs +++ b/src/Lucene.Net/Support/ExceptionHandling/Exceptions/RuntimeExceptions/NullPointerException.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.CompilerServices; using System.Runtime.Serialization; namespace Lucene @@ -34,12 +35,44 @@ namespace Lucene /// null object. NullPointerException objects may be constructed by the virtual machine /// as if suppression were disabled and/or the stack trace was not writable. /// - /// This is a Java compatibility exception, and should be thrown in + /// This is a Java compatibility exception, and may be thrown in /// Lucene.NET everywhere Lucene throws it, however catch blocks should /// always use the method. /// /// catch (Exception ex) when (ex.IsNullPointerException()) /// + /// The static method overloads throw , which is + /// what we should throw in guard clauses. However, there are edge cases where it may make sense to throw + /// instead. One example of this is when in Java an Integer + /// class is set to a primitive int variable. + /// + /// Integer someInt = new Integer(43);
+ /// int primitiveInt = someInt; // Implicit cast by the Java compiler + ///
+ /// If someInt in the above example were set to null, this would still compile, but would + /// throw NullPointerException at runtime. + /// + /// In .NET, Integer is most often translated to int?, making it nullable but keeping it + /// a value type. However setting a nullable int to a nullable one in .NET won't compile. + /// + /// int? someInt = 43;
+ /// int primitiveInt = someInt; // Compile error + ///
+ /// So, to get the same behavior as in Java (provided the nullable cannot be factored away), the + /// appropriate translation would be: + /// + /// int? someInt = 43;
+ /// int primitiveInt;
+ /// if (someInt.HasValue)
+ /// primitiveInt = someInt.Value;
+ /// else
+ /// throw new NullReferenceException(); + ///
+ /// However, do note in most cases it would be better to try to refactor so the nullable + /// (and therefore the exception) isn't required. + /// + /// There are also other edge cases (i.e. null state in the middle of a method where the null value isn't being passed in) + /// where throwing may be more sensible, but this sort of change would need to be tested thoroughly. /// // LUCENENET: It is no longer good practice to use binary serialization. // See: https://github.com/dotnet/corefx/issues/23584#issuecomment-325724568 @@ -48,18 +81,22 @@ namespace Lucene #endif internal class NullPointerException : ArgumentNullException { + [Obsolete("Use NullPointerException.Create() instead.", error: true)] public NullPointerException() { } + [Obsolete("Use NullPointerException.Create() instead.", error: true)] public NullPointerException(string message) : base(message) { } + [Obsolete("Use NullPointerException.Create() instead.", error: true)] public NullPointerException(string message, Exception innerException) : base(message, innerException) { } + [Obsolete("Use NullPointerException.Create() instead.", error: true)] public NullPointerException(Exception cause) : base(cause?.ToString(), cause) { @@ -76,5 +113,31 @@ protected NullPointerException(SerializationInfo info, StreamingContext context) { } #endif + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Exception Create() => new ArgumentNullException(); + + /// + /// LUCENENET: This overload is for a "direct" translation without passing the name of the argument. In cases where + /// there is no message and there is a useful argument name, it would make more senes to call new ArgumentNullExcpetion() directly. + /// Since this class is basically intended as training wheels for those who don't want to bother looking up exception types, + /// this is probably a reasonable default. + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Exception Create(string message) => new ArgumentNullException(paramName: null, message); + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Exception Create(string paramName, string message) => new ArgumentNullException(paramName, message); + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Exception Create(string message, Exception innerException) => new ArgumentNullException(message, innerException); + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Exception Create(Exception cause) => new ArgumentNullException(cause.Message, cause); } }