csharp/71/Cometary/src/Cometary.Expressions/Expressions/LockExpression.cs

LockExpression.cs
using System;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading;

namespace Cometary.Expressions
{
    /// 
    /// Represents a  expression.
    /// 
    public sealed clast LockExpression : Expression
    {
        /// 
        public override bool CanReduce => true;

        /// 
        public override ExpressionType NodeType => ExpressionType.Extension;

        /// 
        public override Type Type => Body.Type;

        /// 
        /// Gets the  that is the body
        /// of the lock block.
        /// 
        public Expression Body { get; }

        /// 
        /// Gets the  that is the object
        /// used to lock the execution of a method.
        /// 
        public Expression Object { get; }

        internal LockExpression(Expression obj, Expression body)
        {
            Object = obj;
            Body = body;
        }

        /// 
        public override Expression Reduce()
        {
            ParameterExpression lockObject = Variable(typeof(object), "lockObject");

            return Block(new[] { lockObject },
                astign(lockObject, Object),
                TryFinally(
                    Block(
                        Call(typeof(Monitor), nameof(Monitor.Enter), null, lockObject),
                        Body
                    ), 
                    Call(typeof(Monitor), nameof(Monitor.Exit), null, lockObject)
                )
            );
        }

        /// 
        public LockExpression Update(Expression obj, Expression body)
        {
            if (body == Body && obj == Object)
                return this;

            return Expressive.Lock(obj, body);
        }

        /// 
        protected override Expression VisitChildren(ExpressionVisitor visitor)
            => Update(visitor.Visit(Object), visitor.Visit(Body));

        /// 
        public override string ToString() => $"lock ({Object}) {{ ... }}";
    }

    partial clast Expressive
    {
        /// 
        /// Creates a  that represents a
        ///  statement.
        /// 
        public static LockExpression Lock(Expression obj, Expression body)
        {
            Requires.NotNull(obj, nameof(obj));
            Requires.NotNull(body, nameof(body));

            if (obj.Type.GetTypeInfo().IsValueType)
                throw new ArgumentException("The given argument must be a reference type.", nameof(obj));

            return new LockExpression(obj, body);
        }
    }
}