ソースを参照

[MVC] Minor TagHelper refactoring (#41454)

* Use ArgumentNullException.ThrowIfNull
   Use ArgumentNullException.ThrowIfNull() where appropriate.
* Seal classes
   Seal internal and private classes where appropriate.
* Use target-typed new expression
  Use target-typed new expression with field initializers.
  Fix whitespace.
* Remove dictionary lookup
   Remove dictionary lookups where the value is already present in a local variable.
* Use string.Join char overload
   Use the char overload for string.Join().
* Set SkipEnabledCheck
   Set SkipEnabledCheck to true for two log statements that are already guarded with an IsEnabled(LogLevel.Debug) check.
* Use for loop instead of foreach
   Use for loop for field that is an array, rather than typing as an IEnumerable<T> and using foreach.
* Use is patterns
   Use is pattern operator.
* Simplify IsWhiteSpace()
   Use the same implementation as UrlResolutionTagHelper.
Martin Costello 3 年 前
コミット
d9327eb223

+ 3 - 11
src/Mvc/Mvc.Razor/src/TagHelpers/TagHelperComponentPropertyActivator.cs

@@ -13,17 +13,12 @@ namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
 /// <summary>
 /// Default implementation of <see cref="ITagHelperComponentPropertyActivator"/>.
 /// </summary>
-internal class TagHelperComponentPropertyActivator : ITagHelperComponentPropertyActivator
+internal sealed class TagHelperComponentPropertyActivator : ITagHelperComponentPropertyActivator
 {
-    private readonly ConcurrentDictionary<Type, PropertyActivator<ViewContext>[]> _propertiesToActivate;
+    private readonly ConcurrentDictionary<Type, PropertyActivator<ViewContext>[]> _propertiesToActivate = new();
     private readonly Func<Type, PropertyActivator<ViewContext>[]> _getPropertiesToActivate = GetPropertiesToActivate;
     private static readonly Func<PropertyInfo, PropertyActivator<ViewContext>> _createActivateInfo = CreateActivateInfo;
 
-    public TagHelperComponentPropertyActivator()
-    {
-        _propertiesToActivate = new ConcurrentDictionary<Type, PropertyActivator<ViewContext>[]>();
-    }
-
     internal void ClearCache()
     {
         _propertiesToActivate.Clear();
@@ -32,10 +27,7 @@ internal class TagHelperComponentPropertyActivator : ITagHelperComponentProperty
     /// <inheritdoc />
     public void Activate(ViewContext context, ITagHelperComponent tagHelperComponent)
     {
-        if (context == null)
-        {
-            throw new ArgumentNullException(nameof(context));
-        }
+        ArgumentNullException.ThrowIfNull(context);
 
         var propertiesToActivate = _propertiesToActivate.GetOrAdd(
             tagHelperComponent.GetType(),

+ 9 - 14
src/Mvc/Mvc.Razor/src/TagHelpers/TagHelperComponentTagHelper.cs

@@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
 public abstract partial class TagHelperComponentTagHelper : TagHelper
 {
     private readonly ILogger _logger;
-    private readonly IEnumerable<ITagHelperComponent> _components;
+    private readonly ITagHelperComponent[] _components;
 
     /// <summary>
     /// Creates a new <see cref="TagHelperComponentTagHelper"/> and orders the
@@ -33,15 +33,8 @@ public abstract partial class TagHelperComponentTagHelper : TagHelper
         ITagHelperComponentManager manager,
         ILoggerFactory loggerFactory)
     {
-        if (manager == null)
-        {
-            throw new ArgumentNullException(nameof(manager));
-        }
-
-        if (loggerFactory == null)
-        {
-            throw new ArgumentNullException(nameof(loggerFactory));
-        }
+        ArgumentNullException.ThrowIfNull(manager);
+        ArgumentNullException.ThrowIfNull(loggerFactory);
 
         _components = manager.Components.OrderBy(p => p.Order).ToArray();
         _logger = loggerFactory.CreateLogger(GetType());
@@ -69,8 +62,9 @@ public abstract partial class TagHelperComponentTagHelper : TagHelper
             PropertyActivator = serviceProvider.GetRequiredService<ITagHelperComponentPropertyActivator>();
         }
 
-        foreach (var component in _components)
+        for (var i = 0; i < _components.Length; i++)
         {
+            var component = _components[i];
             PropertyActivator.Activate(ViewContext, component);
             component.Init(context);
             if (_logger.IsEnabled(LogLevel.Debug))
@@ -83,8 +77,9 @@ public abstract partial class TagHelperComponentTagHelper : TagHelper
     /// <inheritdoc />
     public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
     {
-        foreach (var component in _components)
+        for (var i = 0; i < _components.Length; i++)
         {
+            var component = _components[i];
             await component.ProcessAsync(context, output);
             if (_logger.IsEnabled(LogLevel.Debug))
             {
@@ -95,10 +90,10 @@ public abstract partial class TagHelperComponentTagHelper : TagHelper
 
     private static partial class Log
     {
-        [LoggerMessage(2, LogLevel.Debug, "Tag helper component '{ComponentName}' initialized.", EventName = "TagHelperComponentInitialized")]
+        [LoggerMessage(2, LogLevel.Debug, "Tag helper component '{ComponentName}' initialized.", EventName = "TagHelperComponentInitialized", SkipEnabledCheck = true)]
         public static partial void TagHelperComponentInitialized(ILogger logger, string componentName);
 
-        [LoggerMessage(3, LogLevel.Debug, "Tag helper component '{ComponentName}' processed.", EventName = "TagHelperComponentProcessed")]
+        [LoggerMessage(3, LogLevel.Debug, "Tag helper component '{ComponentName}' processed.", EventName = "TagHelperComponentProcessed", SkipEnabledCheck = true)]
         public static partial void TagHelperComponentProcessed(ILogger logger, string componentName);
     }
 }

+ 31 - 47
src/Mvc/Mvc.Razor/src/TagHelpers/UrlResolutionTagHelper.cs

@@ -52,31 +52,31 @@ public class UrlResolutionTagHelper : TagHelper
     private static readonly char[] ValidAttributeWhitespaceChars =
         new[] { '\t', '\n', '\u000C', '\r', ' ' };
     private static readonly Dictionary<string, string[]> ElementAttributeLookups =
-        new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase)
+        new(StringComparer.OrdinalIgnoreCase)
         {
-                { "a", new[] { "href" } },
-                { "applet", new[] { "archive" } },
-                { "area", new[] { "href" } },
-                { "audio", new[] { "src" } },
-                { "base", new[] { "href" } },
-                { "blockquote", new[] { "cite" } },
-                { "button", new[] { "formaction" } },
-                { "del", new[] { "cite" } },
-                { "embed", new[] { "src" } },
-                { "form", new[] { "action" } },
-                { "html", new[] { "manifest" } },
-                { "iframe", new[] { "src" } },
-                { "img", new[] { "src", "srcset" } },
-                { "input", new[] { "src", "formaction" } },
-                { "ins", new[] { "cite" } },
-                { "link", new[] { "href" } },
-                { "menuitem", new[] { "icon" } },
-                { "object", new[] { "archive", "data" } },
-                { "q", new[] { "cite" } },
-                { "script", new[] { "src" } },
-                { "source", new[] { "src", "srcset" } },
-                { "track", new[] { "src" } },
-                { "video", new[] { "poster", "src" } },
+            { "a", new[] { "href" } },
+            { "applet", new[] { "archive" } },
+            { "area", new[] { "href" } },
+            { "audio", new[] { "src" } },
+            { "base", new[] { "href" } },
+            { "blockquote", new[] { "cite" } },
+            { "button", new[] { "formaction" } },
+            { "del", new[] { "cite" } },
+            { "embed", new[] { "src" } },
+            { "form", new[] { "action" } },
+            { "html", new[] { "manifest" } },
+            { "iframe", new[] { "src" } },
+            { "img", new[] { "src", "srcset" } },
+            { "input", new[] { "src", "formaction" } },
+            { "ins", new[] { "cite" } },
+            { "link", new[] { "href" } },
+            { "menuitem", new[] { "icon" } },
+            { "object", new[] { "archive", "data" } },
+            { "q", new[] { "cite" } },
+            { "script", new[] { "src" } },
+            { "source", new[] { "src", "srcset" } },
+            { "track", new[] { "src" } },
+            { "video", new[] { "poster", "src" } },
         };
 
     /// <summary>
@@ -113,15 +113,8 @@ public class UrlResolutionTagHelper : TagHelper
     /// <inheritdoc />
     public override void Process(TagHelperContext context, TagHelperOutput output)
     {
-        if (context == null)
-        {
-            throw new ArgumentNullException(nameof(context));
-        }
-
-        if (output == null)
-        {
-            throw new ArgumentNullException(nameof(output));
-        }
+        ArgumentNullException.ThrowIfNull(context);
+        ArgumentNullException.ThrowIfNull(output);
 
         if (output.TagName == null)
         {
@@ -149,15 +142,8 @@ public class UrlResolutionTagHelper : TagHelper
     /// <param name="output">The <see cref="TagHelperOutput"/>.</param>
     protected void ProcessUrlAttribute(string attributeName, TagHelperOutput output)
     {
-        if (attributeName == null)
-        {
-            throw new ArgumentNullException(nameof(attributeName));
-        }
-
-        if (output == null)
-        {
-            throw new ArgumentNullException(nameof(output));
-        }
+        ArgumentNullException.ThrowIfNull(attributeName);
+        ArgumentNullException.ThrowIfNull(output);
 
         var attributes = output.Attributes;
         // Read interface .Count once rather than per iteration
@@ -170,8 +156,7 @@ public class UrlResolutionTagHelper : TagHelper
                 continue;
             }
 
-            var stringValue = attribute.Value as string;
-            if (stringValue != null)
+            if (attribute.Value is string stringValue)
             {
                 if (TryResolveUrl(stringValue, resolvedUrl: out string? resolvedUrl))
                 {
@@ -183,8 +168,7 @@ public class UrlResolutionTagHelper : TagHelper
             }
             else
             {
-                var htmlContent = attribute.Value as IHtmlContent;
-                if (htmlContent != null)
+                if (attribute.Value is IHtmlContent htmlContent)
                 {
                     var htmlString = htmlContent as HtmlString;
                     if (htmlString != null)
@@ -343,7 +327,7 @@ public class UrlResolutionTagHelper : TagHelper
         return ValidAttributeWhitespaceChars.AsSpan().IndexOf(ch) != -1;
     }
 
-    private class EncodeFirstSegmentContent : IHtmlContent
+    private sealed class EncodeFirstSegmentContent : IHtmlContent
     {
         private readonly string _firstSegment;
         private readonly int _firstSegmentLength;

+ 4 - 11
src/Mvc/Mvc.TagHelpers/src/CacheTagHelper.cs

@@ -60,15 +60,8 @@ public class CacheTagHelper : CacheTagHelperBase
     /// <inheritdoc />
     public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
     {
-        if (context == null)
-        {
-            throw new ArgumentNullException(nameof(context));
-        }
-
-        if (output == null)
-        {
-            throw new ArgumentNullException(nameof(output));
-        }
+        ArgumentNullException.ThrowIfNull(context);
+        ArgumentNullException.ThrowIfNull(output);
 
         IHtmlContent content;
         if (Enabled)
@@ -219,7 +212,7 @@ public class CacheTagHelper : CacheTagHelperBase
         }
     }
 
-    private class CharBufferTextWriter : TextWriter
+    private sealed class CharBufferTextWriter : TextWriter
     {
         public CharBufferTextWriter()
         {
@@ -246,7 +239,7 @@ public class CacheTagHelper : CacheTagHelperBase
         }
     }
 
-    private class CharBufferHtmlContent : IHtmlContent
+    private sealed class CharBufferHtmlContent : IHtmlContent
     {
         private readonly PagedCharBuffer _buffer;
 

+ 1 - 1
src/Mvc/Mvc.TagHelpers/src/CurrentValues.cs

@@ -5,7 +5,7 @@ using System.Diagnostics;
 
 namespace Microsoft.AspNetCore.Mvc.TagHelpers;
 
-internal class CurrentValues
+internal sealed class CurrentValues
 {
     public CurrentValues(ICollection<string> values)
     {

+ 2 - 5
src/Mvc/Mvc.TagHelpers/src/FileProviderGlobbingDirectory.cs

@@ -6,7 +6,7 @@ using Microsoft.Extensions.FileSystemGlobbing.Abstractions;
 
 namespace Microsoft.AspNetCore.Mvc.TagHelpers;
 
-internal class FileProviderGlobbingDirectory : DirectoryInfoBase
+internal sealed class FileProviderGlobbingDirectory : DirectoryInfoBase
 {
     private const char DirectorySeparatorChar = '/';
     private readonly IFileProvider _fileProvider;
@@ -19,10 +19,7 @@ internal class FileProviderGlobbingDirectory : DirectoryInfoBase
         IFileInfo fileInfo,
         FileProviderGlobbingDirectory parent)
     {
-        if (fileProvider == null)
-        {
-            throw new ArgumentNullException(nameof(fileProvider));
-        }
+        ArgumentNullException.ThrowIfNull(fileProvider);
 
         _fileProvider = fileProvider;
         _fileInfo = fileInfo;

+ 3 - 10
src/Mvc/Mvc.TagHelpers/src/FileProviderGlobbingFile.cs

@@ -6,21 +6,14 @@ using Microsoft.Extensions.FileSystemGlobbing.Abstractions;
 
 namespace Microsoft.AspNetCore.Mvc.TagHelpers;
 
-internal class FileProviderGlobbingFile : FileInfoBase
+internal sealed class FileProviderGlobbingFile : FileInfoBase
 {
     private const char DirectorySeparatorChar = '/';
 
     public FileProviderGlobbingFile(IFileInfo fileInfo, DirectoryInfoBase parent)
     {
-        if (fileInfo == null)
-        {
-            throw new ArgumentNullException(nameof(fileInfo));
-        }
-
-        if (parent == null)
-        {
-            throw new ArgumentNullException(nameof(parent));
-        }
+        ArgumentNullException.ThrowIfNull(fileInfo);
+        ArgumentNullException.ThrowIfNull(parent);
 
         Name = fileInfo.Name;
         ParentDirectory = parent;

+ 5 - 19
src/Mvc/Mvc.TagHelpers/src/GlobbingUrlBuilder.cs

@@ -31,15 +31,8 @@ public class GlobbingUrlBuilder
     /// <param name="requestPathBase">The request path base.</param>
     public GlobbingUrlBuilder(IFileProvider fileProvider, IMemoryCache cache, PathString requestPathBase)
     {
-        if (fileProvider == null)
-        {
-            throw new ArgumentNullException(nameof(fileProvider));
-        }
-
-        if (cache == null)
-        {
-            throw new ArgumentNullException(nameof(cache));
-        }
+        ArgumentNullException.ThrowIfNull(fileProvider);
+        ArgumentNullException.ThrowIfNull(cache);
 
         FileProvider = fileProvider;
         Cache = cache;
@@ -176,7 +169,7 @@ public class GlobbingUrlBuilder
         return (matchedUrls, sizeInBytes);
     }
 
-    private class PathComparer : IComparer<string>
+    private sealed class PathComparer : IComparer<string>
     {
         public int Compare(string x, string y)
         {
@@ -310,15 +303,8 @@ public class GlobbingUrlBuilder
 
     private static bool IsWhiteSpace(string value, int index)
     {
-        for (var i = 0; i < ValidAttributeWhitespaceChars.Length; i++)
-        {
-            if (value[index] == ValidAttributeWhitespaceChars[i])
-            {
-                return true;
-            }
-        }
-
-        return false;
+        var ch = value[index];
+        return ValidAttributeWhitespaceChars.AsSpan().IndexOf(ch) != -1;
     }
 
     private static StringSegment Trim(StringSegment value)

+ 35 - 35
src/Mvc/Mvc.TagHelpers/src/InputTagHelper.cs

@@ -20,46 +20,46 @@ public class InputTagHelper : TagHelper
 
     // Mapping from datatype names and data annotation hints to values for the <input/> element's "type" attribute.
     private static readonly Dictionary<string, string> _defaultInputTypes =
-        new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
-        {
-                { "HiddenInput", InputType.Hidden.ToString().ToLowerInvariant() },
-                { "Password", InputType.Password.ToString().ToLowerInvariant() },
-                { "Text", InputType.Text.ToString().ToLowerInvariant() },
-                { "PhoneNumber", "tel" },
-                { "Url", "url" },
-                { "EmailAddress", "email" },
-                { "Date", "date" },
-                { "DateTime", "datetime-local" },
-                { "DateTime-local", "datetime-local" },
-                { nameof(DateTimeOffset), "text" },
-                { "Time", "time" },
-                { "Week", "week" },
-                { "Month", "month" },
-                { nameof(Byte), "number" },
-                { nameof(SByte), "number" },
-                { nameof(Int16), "number" },
-                { nameof(UInt16), "number" },
-                { nameof(Int32), "number" },
-                { nameof(UInt32), "number" },
-                { nameof(Int64), "number" },
-                { nameof(UInt64), "number" },
-                { nameof(Single), InputType.Text.ToString().ToLowerInvariant() },
-                { nameof(Double), InputType.Text.ToString().ToLowerInvariant() },
-                { nameof(Boolean), InputType.CheckBox.ToString().ToLowerInvariant() },
-                { nameof(Decimal), InputType.Text.ToString().ToLowerInvariant() },
-                { nameof(String), InputType.Text.ToString().ToLowerInvariant() },
-                { nameof(IFormFile), "file" },
-                { TemplateRenderer.IEnumerableOfIFormFileName, "file" },
+        new(StringComparer.OrdinalIgnoreCase)
+        {
+            { "HiddenInput", InputType.Hidden.ToString().ToLowerInvariant() },
+            { "Password", InputType.Password.ToString().ToLowerInvariant() },
+            { "Text", InputType.Text.ToString().ToLowerInvariant() },
+            { "PhoneNumber", "tel" },
+            { "Url", "url" },
+            { "EmailAddress", "email" },
+            { "Date", "date" },
+            { "DateTime", "datetime-local" },
+            { "DateTime-local", "datetime-local" },
+            { nameof(DateTimeOffset), "text" },
+            { "Time", "time" },
+            { "Week", "week" },
+            { "Month", "month" },
+            { nameof(Byte), "number" },
+            { nameof(SByte), "number" },
+            { nameof(Int16), "number" },
+            { nameof(UInt16), "number" },
+            { nameof(Int32), "number" },
+            { nameof(UInt32), "number" },
+            { nameof(Int64), "number" },
+            { nameof(UInt64), "number" },
+            { nameof(Single), InputType.Text.ToString().ToLowerInvariant() },
+            { nameof(Double), InputType.Text.ToString().ToLowerInvariant() },
+            { nameof(Boolean), InputType.CheckBox.ToString().ToLowerInvariant() },
+            { nameof(Decimal), InputType.Text.ToString().ToLowerInvariant() },
+            { nameof(String), InputType.Text.ToString().ToLowerInvariant() },
+            { nameof(IFormFile), "file" },
+            { TemplateRenderer.IEnumerableOfIFormFileName, "file" },
         };
 
     // Mapping from <input/> element's type to RFC 3339 date and time formats.
     private static readonly Dictionary<string, string> _rfc3339Formats =
-        new Dictionary<string, string>(StringComparer.Ordinal)
+        new(StringComparer.Ordinal)
         {
-                { "date", "{0:yyyy-MM-dd}" },
-                { "datetime", @"{0:yyyy-MM-ddTHH\:mm\:ss.fffK}" },
-                { "datetime-local", @"{0:yyyy-MM-ddTHH\:mm\:ss.fff}" },
-                { "time", @"{0:HH\:mm\:ss.fff}" },
+            { "date", "{0:yyyy-MM-dd}" },
+            { "datetime", @"{0:yyyy-MM-ddTHH\:mm\:ss.fffK}" },
+            { "datetime-local", @"{0:yyyy-MM-ddTHH\:mm\:ss.fff}" },
+            { "time", @"{0:HH\:mm\:ss.fff}" },
         };
 
     /// <summary>

+ 15 - 53
src/Mvc/Mvc.TagHelpers/src/TagHelperOutputExtensions.cs

@@ -41,20 +41,9 @@ public static class TagHelperOutputExtensions
         string attributeName,
         TagHelperContext context)
     {
-        if (tagHelperOutput == null)
-        {
-            throw new ArgumentNullException(nameof(tagHelperOutput));
-        }
-
-        if (attributeName == null)
-        {
-            throw new ArgumentNullException(nameof(attributeName));
-        }
-
-        if (context == null)
-        {
-            throw new ArgumentNullException(nameof(context));
-        }
+        ArgumentNullException.ThrowIfNull(tagHelperOutput);
+        ArgumentNullException.ThrowIfNull(attributeName);
+        ArgumentNullException.ThrowIfNull(context);
 
         if (!tagHelperOutput.Attributes.ContainsName(attributeName))
         {
@@ -95,15 +84,8 @@ public static class TagHelperOutputExtensions
     /// are not overridden; "class" attributes are merged with spaces.</remarks>
     public static void MergeAttributes(this TagHelperOutput tagHelperOutput, TagBuilder tagBuilder)
     {
-        if (tagHelperOutput == null)
-        {
-            throw new ArgumentNullException(nameof(tagHelperOutput));
-        }
-
-        if (tagBuilder == null)
-        {
-            throw new ArgumentNullException(nameof(tagBuilder));
-        }
+        ArgumentNullException.ThrowIfNull(tagHelperOutput);
+        ArgumentNullException.ThrowIfNull(tagBuilder);
 
         foreach (var attribute in tagBuilder.Attributes)
         {
@@ -136,15 +118,8 @@ public static class TagHelperOutputExtensions
         this TagHelperOutput tagHelperOutput,
         IEnumerable<TagHelperAttribute> attributes)
     {
-        if (tagHelperOutput == null)
-        {
-            throw new ArgumentNullException(nameof(tagHelperOutput));
-        }
-
-        if (attributes == null)
-        {
-            throw new ArgumentNullException(nameof(attributes));
-        }
+        ArgumentNullException.ThrowIfNull(tagHelperOutput);
+        ArgumentNullException.ThrowIfNull(attributes);
 
         foreach (var attribute in attributes.ToArray())
         {
@@ -164,10 +139,7 @@ public static class TagHelperOutputExtensions
         string classValue,
         HtmlEncoder htmlEncoder)
     {
-        if (tagHelperOutput == null)
-        {
-            throw new ArgumentNullException(nameof(tagHelperOutput));
-        }
+        ArgumentNullException.ThrowIfNull(tagHelperOutput);
 
         if (string.IsNullOrEmpty(classValue))
         {
@@ -226,10 +198,7 @@ public static class TagHelperOutputExtensions
         string classValue,
         HtmlEncoder htmlEncoder)
     {
-        if (tagHelperOutput == null)
-        {
-            throw new ArgumentNullException(nameof(tagHelperOutput));
-        }
+        ArgumentNullException.ThrowIfNull(tagHelperOutput);
 
         var encodedSpaceChars = SpaceChars.Where(x => !x.Equals('\u0020')).Select(x => htmlEncoder.Encode(x.ToString())).ToArray();
 
@@ -254,7 +223,7 @@ public static class TagHelperOutputExtensions
 
         if (string.Equals(currentClassValue, encodedClassValue, StringComparison.Ordinal))
         {
-            tagHelperOutput.Attributes.Remove(tagHelperOutput.Attributes["class"]);
+            tagHelperOutput.Attributes.Remove(classAttribute);
             return;
         }
 
@@ -276,12 +245,12 @@ public static class TagHelperOutputExtensions
 
         if (listOfClasses.Count > 0)
         {
-            var joinedClasses = new HtmlString(string.Join(" ", listOfClasses));
+            var joinedClasses = new HtmlString(string.Join(' ', listOfClasses));
             tagHelperOutput.Attributes.SetAttribute(classAttribute.Name, joinedClasses);
         }
         else
         {
-            tagHelperOutput.Attributes.Remove(tagHelperOutput.Attributes["class"]);
+            tagHelperOutput.Attributes.Remove(classAttribute);
         }
     }
 
@@ -368,7 +337,7 @@ public static class TagHelperOutputExtensions
         return -1;
     }
 
-    private class ClassAttributeHtmlContent : IHtmlContent
+    private sealed class ClassAttributeHtmlContent : IHtmlContent
     {
         private readonly object _left;
         private readonly string _right;
@@ -381,15 +350,8 @@ public static class TagHelperOutputExtensions
 
         public void WriteTo(TextWriter writer, HtmlEncoder encoder)
         {
-            if (writer == null)
-            {
-                throw new ArgumentNullException(nameof(writer));
-            }
-
-            if (encoder == null)
-            {
-                throw new ArgumentNullException(nameof(encoder));
-            }
+            ArgumentNullException.ThrowIfNull(writer);
+            ArgumentNullException.ThrowIfNull(encoder);
 
             // Write out "{left} {right}" in the common nothing-empty case.
             var wroteLeft = false;