File: System\Text\RegularExpressions\RegexMatchTimeoutException.cs
Web Access
Project: src\src\libraries\System.Text.RegularExpressions\src\System.Text.RegularExpressions.csproj (System.Text.RegularExpressions)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.ComponentModel;
using System.Runtime.Serialization;
 
namespace System.Text.RegularExpressions
{
    /// <summary>
    /// The exception that is thrown when the execution time of a regular expression pattern-matching
    /// method exceeds its time-out interval.
    /// </summary>
    /// <remarks>
    /// <para>
    /// The presence of a <see cref="RegexMatchTimeoutException"/> exception generally indicates one
    /// of the following conditions:
    /// </para>
    /// <list type="bullet">
    ///   <item>
    ///       The regular expression engine is backtracking excessively as it attempts to match the input
    ///       text to the regular expression pattern.
    ///   </item>
    ///   <item>
    ///       The time-out interval has been set too low, especially given high machine load.
    ///   </item>
    /// </list>
    /// <para>
    /// The way in which an exception handler handles an exception depends on the cause of the exception:
    /// </para>
    /// <para>
    /// If the time-out results from excessive backtracking, your exception handler should abandon the
    /// attempt to match the input and inform the user that a time-out has occurred in the regular
    /// expression pattern-matching method. If possible, information about the regular expression pattern,
    /// which is available from the <see cref="Pattern"/> property, and the input that caused excessive
    /// backtracking, which is available from the <see cref="Input"/> property, should be logged so that
    /// the issue can be investigated and the regular expression pattern modified. Time-outs due to
    /// excessive backtracking are always reproducible.
    /// </para>
    /// <para>
    /// If the time-out results from setting the time-out threshold too low, you can increase the time-out
    /// interval and retry the matching operation. The current time-out interval is available from the
    /// <see cref="MatchTimeout"/> property. When a <see cref="RegexMatchTimeoutException"/> exception is
    /// thrown, the regular expression engine maintains its state so that any future invocations return the
    /// same result, as if the exception did not occur. The recommended pattern is to wait for a brief,
    /// random time interval after the exception is thrown before calling the matching method again. This
    /// can be repeated several times. However, the number of repetitions should be small in case the
    /// time-out is caused by excessive backtracking.
    /// </para>
    /// </remarks>
    [Serializable]
    [System.Runtime.CompilerServices.TypeForwardedFrom("System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
    public class RegexMatchTimeoutException : TimeoutException, ISerializable
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="RegexMatchTimeoutException"/> class with
        /// information about the regular expression pattern, the input text, and the time-out interval.
        /// </summary>
        /// <param name="regexInput">The input text processed by the regular expression engine when the
        /// time-out occurred.</param>
        /// <param name="regexPattern">The pattern used by the regular expression engine when the time-out
        /// occurred.</param>
        /// <param name="matchTimeout">The time-out interval.</param>
        /// <remarks>
        /// The <paramref name="regexInput"/>, <paramref name="regexPattern"/>, and
        /// <paramref name="matchTimeout"/> values are assigned to the <see cref="Input"/>,
        /// <see cref="Pattern"/>, and <see cref="MatchTimeout"/> properties of the new
        /// <see cref="RegexMatchTimeoutException"/> object.
        /// </remarks>
        public RegexMatchTimeoutException(string regexInput, string regexPattern, TimeSpan matchTimeout)
            : base(SR.RegexMatchTimeoutException_Occurred)
        {
            Input = regexInput;
            Pattern = regexPattern;
            MatchTimeout = matchTimeout;
        }
 
        /// <summary>
        /// Initializes a new instance of the <see cref="RegexMatchTimeoutException"/> class with a
        /// system-supplied message.
        /// </summary>
        /// <remarks>
        /// This constructor initializes the <see cref="Exception.Message"/> property of the new instance
        /// to a system-supplied message that describes the error. This message is localized for the
        /// current system culture.
        /// </remarks>
        public RegexMatchTimeoutException() : base(SR.RegexMatchTimeoutException_Occurred) { }
 
        /// <summary>
        /// Initializes a new instance of the <see cref="RegexMatchTimeoutException"/> class with the
        /// specified message string.
        /// </summary>
        /// <param name="message">A string that describes the exception.</param>
        /// <remarks>
        /// The <paramref name="message"/> string is assigned to the
        /// <see cref="Exception.Message"/> property. The string should be localized for the current
        /// culture.
        /// </remarks>
        public RegexMatchTimeoutException(string message) : base(message ?? SR.RegexMatchTimeoutException_Occurred) { }
 
        /// <summary>
        /// Initializes a new instance of the <see cref="RegexMatchTimeoutException"/> class with a
        /// specified error message and a reference to the inner exception that is the cause of this
        /// exception.
        /// </summary>
        /// <param name="message">A string that describes the exception.</param>
        /// <param name="inner">The exception that is the cause of the current exception.</param>
        /// <remarks>
        /// <para>
        /// Typically, you use this overload to handle an exception in a <c>try</c>/<c>catch</c> block.
        /// The <paramref name="inner"/> parameter should be a reference to the exception object handled
        /// in the <c>catch</c> block, or it can be <see langword="null"/>. This value is then assigned
        /// to the <see cref="Exception.InnerException"/> property.
        /// </para>
        /// <para>
        /// The <paramref name="message"/> string is assigned to the
        /// <see cref="Exception.Message"/> property. The string should be localized for the current
        /// culture.
        /// </para>
        /// </remarks>
        public RegexMatchTimeoutException(string message, Exception inner) : base(message ?? SR.RegexMatchTimeoutException_Occurred, inner) { }
 
        /// <summary>
        /// Initializes a new instance of the <see cref="RegexMatchTimeoutException"/> class with
        /// serialized data.
        /// </summary>
        /// <param name="info">The object that contains the serialized data.</param>
        /// <param name="context">The stream that contains the serialized data.</param>
        [Obsolete(Obsoletions.LegacyFormatterImplMessage, DiagnosticId = Obsoletions.LegacyFormatterImplDiagId, UrlFormat = Obsoletions.SharedUrlFormat)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        protected RegexMatchTimeoutException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            Input = info.GetString("regexInput")!;
            Pattern = info.GetString("regexPattern")!;
            MatchTimeout = new TimeSpan(info.GetInt64("timeoutTicks"));
        }
 
        /// <summary>
        /// Populates a <see cref="SerializationInfo"/> object with the data needed to serialize a
        /// <see cref="RegexMatchTimeoutException"/> object.
        /// </summary>
        /// <param name="info">The serialization information object to populate with data.</param>
        /// <param name="context">The destination for this serialization.</param>
        [Obsolete(Obsoletions.LegacyFormatterImplMessage, DiagnosticId = Obsoletions.LegacyFormatterImplDiagId, UrlFormat = Obsoletions.SharedUrlFormat)]
        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info, context);
            info.AddValue("regexInput", Input);
            info.AddValue("regexPattern", Pattern);
            info.AddValue("timeoutTicks", MatchTimeout.Ticks);
        }
 
        /// <summary>
        /// Gets the input text that the regular expression engine was processing when the time-out
        /// occurred.
        /// </summary>
        /// <value>The regular expression input text.</value>
        /// <remarks>
        /// <para>
        /// This property reflects the value of the <c>regexInput</c> parameter of the
        /// <see cref="RegexMatchTimeoutException(string, string, TimeSpan)"/> constructor. If this
        /// parameter is not explicitly initialized in a constructor call, its value is
        /// <see cref="string.Empty"/>.
        /// </para>
        /// <para>
        /// When the exception is thrown by the regular expression engine, the value of the
        /// <see cref="Input"/> property reflects the entire input string passed to the regular
        /// expression engine. It does not reflect a partial string, such as the substring that the
        /// engine searches in the call to a method such as
        /// <see cref="Regex.Match(string, int)"/>.
        /// </para>
        /// </remarks>
        public string Input { get; } = string.Empty;
 
        /// <summary>
        /// Gets the regular expression pattern that was used in the matching operation when the time-out
        /// occurred.
        /// </summary>
        /// <value>The regular expression pattern.</value>
        /// <remarks>
        /// This property reflects the value of the <c>regexPattern</c> parameter of the
        /// <see cref="RegexMatchTimeoutException(string, string, TimeSpan)"/> constructor. If the
        /// parameter is not properly initialized in a constructor call, its value is
        /// <see cref="string.Empty"/>.
        /// </remarks>
        public string Pattern { get; } = string.Empty;
 
        /// <summary>Gets the time-out interval for a regular expression match.</summary>
        /// <value>The time-out interval.</value>
        /// <remarks>
        /// <para>
        /// This property reflects the value of the <c>matchTimeout</c> parameter of the
        /// <see cref="RegexMatchTimeoutException(string, string, TimeSpan)"/> constructor. If the
        /// parameter is not properly initialized in a constructor call, its value is
        /// <c>TimeSpan.FromTicks(-1)</c>.
        /// </para>
        /// <para>
        /// The value of this property reflects the time-out interval set in the call to the
        /// <see cref="Regex"/> constructor or static method. It does not reflect the exact interval
        /// that has elapsed from the beginning of the method call to the time the exception is thrown.
        /// </para>
        /// </remarks>
        public TimeSpan MatchTimeout { get; } = TimeSpan.FromTicks(-1);
    }
}