File: System\Linq\Expressions\CatchBlock.cs
Web Access
Project: src\src\libraries\System.Linq.Expressions\src\System.Linq.Expressions.csproj (System.Linq.Expressions)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Diagnostics;
using System.Dynamic.Utils;
 
namespace System.Linq.Expressions
{
    /// <summary>
    /// Represents a catch statement in a try block.
    /// This must have the same return type (i.e., the type of <see cref="Body"/>) as the try block it is associated with.
    /// </summary>
    [DebuggerTypeProxy(typeof(Expression.CatchBlockProxy))]
    public sealed class CatchBlock
    {
        internal CatchBlock(Type test, ParameterExpression? variable, Expression body, Expression? filter)
        {
            Test = test;
            Variable = variable;
            Body = body;
            Filter = filter;
        }
 
        /// <summary>
        /// Gets a reference to the <see cref="Exception"/> object caught by this handler.
        /// </summary>
        public ParameterExpression? Variable { get; }
 
        /// <summary>
        /// Gets the type of <see cref="Exception"/> this handler catches.
        /// </summary>
        public Type Test { get; }
 
        /// <summary>
        /// Gets the body of the catch block.
        /// </summary>
        public Expression Body { get; }
 
        /// <summary>
        /// Gets the body of the <see cref="CatchBlock"/>'s filter.
        /// </summary>
        public Expression? Filter { get; }
 
        /// <summary>
        /// Returns a <see cref="string"/> that represents the current <see cref="object"/>.
        /// </summary>
        /// <returns>A <see cref="string"/> that represents the current <see cref="object"/>.</returns>
        public override string ToString()
        {
            return ExpressionStringBuilder.CatchBlockToString(this);
        }
 
        /// <summary>
        /// Creates a new expression that is like this one, but using the
        /// supplied children. If all of the children are the same, it will
        /// return this expression.
        /// </summary>
        /// <param name="variable">The <see cref="Variable"/> property of the result.</param>
        /// <param name="filter">The <see cref="Filter"/> property of the result.</param>
        /// <param name="body">The <see cref="Body"/> property of the result.</param>
        /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
        public CatchBlock Update(ParameterExpression? variable, Expression? filter, Expression body)
        {
            if (variable == Variable && filter == Filter && body == Body)
            {
                return this;
            }
            return Expression.MakeCatchBlock(Test, variable, body, filter);
        }
    }
 
    public partial class Expression
    {
        /// <summary>
        /// Creates a <see cref="CatchBlock"/> representing a catch statement.
        /// The <see cref="Type"/> of object to be caught can be specified but no reference to the object
        /// will be available for use in the <see cref="CatchBlock"/>.
        /// </summary>
        /// <param name="type">The <see cref="Type"/> of <see cref="Exception"/> this <see cref="CatchBlock"/> will handle.</param>
        /// <param name="body">The body of the catch statement.</param>
        /// <returns>The created <see cref="CatchBlock"/>.</returns>
        public static CatchBlock Catch(Type type, Expression body)
        {
            return MakeCatchBlock(type, null, body, filter: null);
        }
 
        /// <summary>
        /// Creates a <see cref="CatchBlock"/> representing a catch statement with a reference to the caught object for use in the handler body.
        /// </summary>
        /// <param name="variable">A <see cref="ParameterExpression"/> representing a reference to the <see cref="Exception"/> object caught by this handler.</param>
        /// <param name="body">The body of the catch statement.</param>
        /// <returns>The created <see cref="CatchBlock"/>.</returns>
        public static CatchBlock Catch(ParameterExpression variable, Expression body)
        {
            ArgumentNullException.ThrowIfNull(variable);
            return MakeCatchBlock(variable.Type, variable, body, filter: null);
        }
 
        /// <summary>
        /// Creates a <see cref="CatchBlock"/> representing a catch statement with
        /// an <see cref="Exception"/> filter but no reference to the caught <see cref="Exception"/> object.
        /// </summary>
        /// <param name="type">The <see cref="Type"/> of <see cref="Exception"/> this <see cref="CatchBlock"/> will handle.</param>
        /// <param name="body">The body of the catch statement.</param>
        /// <param name="filter">The body of the <see cref="Exception"/> filter.</param>
        /// <returns>The created <see cref="CatchBlock"/>.</returns>
        public static CatchBlock Catch(Type type, Expression body, Expression? filter)
        {
            return MakeCatchBlock(type, null, body, filter);
        }
 
        /// <summary>
        /// Creates a <see cref="CatchBlock"/> representing a catch statement with
        /// an <see cref="Exception"/> filter and a reference to the caught <see cref="Exception"/> object.
        /// </summary>
        /// <param name="variable">A <see cref="ParameterExpression"/> representing a reference to the <see cref="Exception"/> object caught by this handler.</param>
        /// <param name="body">The body of the catch statement.</param>
        /// <param name="filter">The body of the <see cref="Exception"/> filter.</param>
        /// <returns>The created <see cref="CatchBlock"/>.</returns>
        public static CatchBlock Catch(ParameterExpression variable, Expression body, Expression? filter)
        {
            ArgumentNullException.ThrowIfNull(variable);
            return MakeCatchBlock(variable.Type, variable, body, filter);
        }
 
        /// <summary>
        /// Creates a <see cref="CatchBlock"/> representing a catch statement with the specified elements.
        /// </summary>
        /// <param name="type">The <see cref="Type"/> of <see cref="Exception"/> this <see cref="CatchBlock"/> will handle.</param>
        /// <param name="variable">A <see cref="ParameterExpression"/> representing a reference to the <see cref="Exception"/> object caught by this handler.</param>
        /// <param name="body">The body of the catch statement.</param>
        /// <param name="filter">The body of the <see cref="Exception"/> filter.</param>
        /// <returns>The created <see cref="CatchBlock"/>.</returns>
        /// <remarks><paramref name="type"/> must be non-null and match the type of <paramref name="variable"/> (if it is supplied).</remarks>
        public static CatchBlock MakeCatchBlock(Type type, ParameterExpression? variable, Expression body, Expression? filter)
        {
            ArgumentNullException.ThrowIfNull(type);
            ContractUtils.Requires(variable == null || TypeUtils.AreEquivalent(variable.Type, type), nameof(variable));
            if (variable == null)
            {
                TypeUtils.ValidateType(type, nameof(type));
            }
            else if (variable.IsByRef)
            {
                throw Error.VariableMustNotBeByRef(variable, variable.Type, nameof(variable));
            }
            ExpressionUtils.RequiresCanRead(body, nameof(body));
            if (filter != null)
            {
                ExpressionUtils.RequiresCanRead(filter, nameof(filter));
                if (filter.Type != typeof(bool)) throw Error.ArgumentMustBeBoolean(nameof(filter));
            }
 
            return new CatchBlock(type, variable, body, filter);
        }
    }
}