/// <summary>
        /// Write expression type(not element)
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="expression"></param>
        protected override void WriteExpressionType(XmlWriter writer, XacmlExpression expression) {
            Type applyElemType = expression.Property.GetType();
            if (applyElemType == typeof(XacmlVariableReference)) {
                writer.WriteStartElement(XacmlConstants.Prefixes.Policy, XacmlConstants.ElementNames.VariableReference, this.version.NamespacePolicy);
                writer.WriteAttributeString(XacmlConstants.AttributeNames.VariableId, (expression.Property as XacmlVariableReference).VariableReference);
                writer.WriteEndElement();
                return;
            }
            else if (applyElemType == typeof(XacmlAttributeSelector)) {
                XacmlAttributeSelector prop = expression.Property as XacmlAttributeSelector;
                writer.WriteStartElement(XacmlConstants.Prefixes.Policy, XacmlConstants.ElementNames.AttributeSelector, this.version.NamespacePolicy);
                writer.WriteAttributeString(XacmlConstants.AttributeNames.RequestContextPath, prop.Path);
                writer.WriteAttributeString(XacmlConstants.AttributeNames.DataType, prop.DataType.OriginalString);
                writer.WriteAttributeString(XacmlConstants.AttributeNames.DataType, XmlConvert.ToString(prop.MustBePresent.HasValue && prop.MustBePresent.Value));

                writer.WriteEndElement();
                return;
            }
            else if (applyElemType == typeof(XacmlAttributeDesignator)) {
                this.WriteAttributeDesignator(writer, expression.Property as XacmlAttributeDesignator);
                return;
            }
            else if (applyElemType == typeof(XacmlAttributeValue)) {
                this.WriteAttributeValue(writer, expression.Property as XacmlAttributeValue);
                return;
            }
            else if (applyElemType == typeof(XacmlFunction)) {
                writer.WriteStartElement(XacmlConstants.Prefixes.Policy, XacmlConstants.ElementNames.Function, this.version.NamespacePolicy);
                writer.WriteAttributeString(XacmlConstants.AttributeNames.FunctionId, (expression.Property as XacmlFunction).FunctionId.OriginalString);
                writer.WriteEndElement();
                return;
            }
            else if (applyElemType == typeof(XacmlApply)) {
                this.WriteApply(writer, expression.Property as XacmlApply);
                return;
            }
        }
        /// <summary>
        /// Reads the condition
        /// </summary>
        /// <param name="reader">The reader.</param>
        /// <returns></returns>
        protected override XacmlExpression ReadCondition(XmlReader reader) {
            Contract.Requires<ArgumentNullException>(reader != null, "reader");
            Contract.Requires<XmlException>(reader.IsStartElement(XacmlConstants.ElementNames.Condition, this.version.NamespacePolicy));

            reader.ReadStartElement(XacmlConstants.ElementNames.Condition, this.version.NamespacePolicy);

            XacmlExpression condition = new XacmlExpression() {
                Property = this.ReadExpressionType(reader)
            };

            reader.ReadEndElement();
            return condition;
        }
        public bool? ConditionEvaluate(XacmlExpression condition) {
            Contract.Requires<ArgumentNullException>(condition != null);

            try {
                object conditionResult = this.ExpressionEvaluate(condition.Property);
                return conditionResult as bool?;
            }
            catch (XacmlIndeterminateException ex) {
                Diagnostic.DiagnosticTools.ExceptionUtil.TraceHandledException(ex, System.Diagnostics.TraceEventType.Warning);
                return null;
            }
            catch (InvalidOperationException ex) {
                Diagnostic.DiagnosticTools.ExceptionUtil.TraceHandledException(ex, System.Diagnostics.TraceEventType.Warning);
                return null;
            }
        }
        /// <summary>
        /// Writes the condition.
        /// </summary>
        /// <param name="writer">The writer.</param>
        /// <param name="apply">The apply.</param>
        protected virtual void WriteCondition(XmlWriter writer, XacmlExpression expression) {
            Contract.Requires<ArgumentNullException>(writer != null);
            Contract.Requires<ArgumentNullException>(expression != null);

            writer.WriteStartElement(XacmlConstants.Prefixes.Policy, XacmlConstants.ElementNames.Condition, this.version.NamespacePolicy);
            this.WriteApplyType(writer, expression.Property as XacmlApply); // TODO:
            writer.WriteEndElement();
        }
        /// <summary>
        /// Reads the condition_2_0.
        /// </summary>
        /// <param name="reader">The reader.</param>
        /// <returns></returns>
        /// <exception cref="XacmlSerializationException">Wrong VariableDefinition element content</exception>
        protected override XacmlExpression ReadCondition(XmlReader reader) {
            Contract.Requires<ArgumentNullException>(reader != null, "reader");
            Contract.Requires<XmlException>(reader.IsStartElement(XacmlConstants.ElementNames.Condition, this.version.NamespacePolicy));

            reader.ReadStartElement(XacmlConstants.ElementNames.Condition, this.version.NamespacePolicy);

            XacmlExpression condition = new XacmlExpression();

            if (reader.IsStartElement(XacmlConstants.ElementNames.VariableReference, this.version.NamespacePolicy)) {
                condition.Property = this.ReadOptional(XacmlConstants.ElementNames.VariableReference, this.version.NamespacePolicy,
                            new ReadElement<XacmlVariableReference>(
                                o => {
                                    string res = this.ReadAttribute<string>(reader, XacmlConstants.AttributeNames.VariableId);
                                    reader.Read();
                                    return new XacmlVariableReference(res);
                                }
                            ), reader);
            }
            else if (reader.IsStartElement(XacmlConstants.ElementNames.AttributeSelector, this.version.NamespacePolicy)) {
                condition.Property = this.ReadOptional(XacmlConstants.ElementNames.AttributeSelector, this.version.NamespacePolicy, this.ReadAttributeSelector, reader);
            }
            else if (reader.IsStartElement(XacmlConstants.ElementNames.ResourceAttributeDesignator, this.version.NamespacePolicy)) {
                condition.Property = this.ReadOptional(XacmlConstants.ElementNames.ResourceAttributeDesignator, this.version.NamespacePolicy, this.ReadAttributeDesignator, reader);
            }
            else if (reader.IsStartElement(XacmlConstants.ElementNames.ActionAttributeDesignator, this.version.NamespacePolicy)) {
                condition.Property = this.ReadOptional(XacmlConstants.ElementNames.ActionAttributeDesignator, this.version.NamespacePolicy, this.ReadAttributeDesignator, reader);
            }
            else if (reader.IsStartElement(XacmlConstants.ElementNames.EnvironmentAttributeDesignator, this.version.NamespacePolicy)) {
                condition.Property = this.ReadOptional(XacmlConstants.ElementNames.EnvironmentAttributeDesignator, this.version.NamespacePolicy, this.ReadAttributeDesignator, reader);
            }
            else if (reader.IsStartElement(XacmlConstants.ElementNames.SubjectAttributeDesignator, this.version.NamespacePolicy)) {
                condition.Property = this.ReadOptional(XacmlConstants.ElementNames.SubjectAttributeDesignator, this.version.NamespacePolicy, this.ReadAttributeDesignator, reader);
            }
            else if (reader.IsStartElement(XacmlConstants.ElementNames.AttributeValue, this.version.NamespacePolicy)) {
                condition.Property = this.ReadOptional(XacmlConstants.ElementNames.AttributeValue, this.version.NamespacePolicy, this.ReadAttributeValue, reader);
            }
            else if (reader.IsStartElement(XacmlConstants.ElementNames.Function, this.version.NamespacePolicy)) {
                condition.Property = this.ReadOptional(XacmlConstants.ElementNames.Function, this.version.NamespacePolicy, this.ReadFunction, reader);
            }
            else if (reader.IsStartElement(XacmlConstants.ElementNames.Apply, this.version.NamespacePolicy)) {
                condition.Property = this.ReadOptional(XacmlConstants.ElementNames.Apply, this.version.NamespacePolicy, this.ReadApply, reader);
            }
            else {
                throw Diagnostic.DiagnosticTools.ExceptionUtil.ThrowHelperError(new XacmlSerializationException("Wrong VariableDefinition element content"));
            }

            reader.ReadEndElement();
            return condition;
        }
        /// <summary>
        /// Write expression type(not element)
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="expression"></param>
        protected virtual void WriteExpressionType(XmlWriter writer, XacmlExpression expression) {
            Contract.Requires<ArgumentNullException>(writer != null);
            Contract.Requires<ArgumentNullException>(expression != null);

            Type applyElemType = expression.Property.GetType();
            if (applyElemType == typeof(XacmlVariableReference)) {
                writer.WriteStartElement(XacmlConstants.Prefixes.Policy, XacmlConstants.ElementNames.VariableReference, this.version.NamespacePolicy);
                writer.WriteAttributeString(XacmlConstants.AttributeNames.VariableId, (expression.Property as XacmlVariableReference).VariableReference);
                writer.WriteEndElement();
                return;
            }
            else if (applyElemType == typeof(XacmlAttributeSelector)) {
                XacmlAttributeSelector prop = expression.Property as XacmlAttributeSelector;
                writer.WriteStartElement(XacmlConstants.Prefixes.Policy, XacmlConstants.ElementNames.AttributeSelector, this.version.NamespacePolicy);
                writer.WriteAttributeString(XacmlConstants.AttributeNames.RequestContextPath, prop.Path);
                writer.WriteAttributeString(XacmlConstants.AttributeNames.DataType, prop.DataType.OriginalString);

                if (prop.MustBePresent.HasValue) {
                    writer.WriteAttributeString(XacmlConstants.AttributeNames.DataType, XmlConvert.ToString(prop.MustBePresent.Value));
                }

                writer.WriteEndElement();
                return;
            }
            else if (applyElemType == typeof(XacmlResourceAttributeDesignator)) {
                this.WriteAttributeDesignator(writer, expression.Property as XacmlResourceAttributeDesignator);
                return;
            }
            else if (applyElemType == typeof(XacmlActionAttributeDesignator)) {
                this.WriteAttributeDesignator(writer, expression.Property as XacmlActionAttributeDesignator);
                return;
            }
            else if (applyElemType == typeof(XacmlEnvironmentAttributeDesignator)) {
                this.WriteAttributeDesignator(writer, expression.Property as XacmlEnvironmentAttributeDesignator);
                return;
            }
            else if (applyElemType == typeof(XacmlSubjectAttributeDesignator)) {
                this.WriteAttributeDesignator(writer, expression.Property as XacmlSubjectAttributeDesignator);
                return;
            }
            else if (applyElemType == typeof(XacmlAttributeValue)) {
                this.WriteAttributeValue(writer, expression.Property as XacmlAttributeValue);
                return;
            }
            else if (applyElemType == typeof(XacmlFunction)) {
                writer.WriteStartElement(XacmlConstants.Prefixes.Policy, XacmlConstants.ElementNames.Function, this.version.NamespacePolicy);
                writer.WriteAttributeString(XacmlConstants.AttributeNames.FunctionId, (expression.Property as XacmlFunction).FunctionId.OriginalString);
                writer.WriteEndElement();
                return;
            }
            else if (applyElemType == typeof(XacmlApply)) {
                this.WriteApply(writer, expression.Property as XacmlApply);
                return;
            }
        }
        /// <summary>
        /// Writes the condition.
        /// </summary>
        /// <param name="writer">The writer.</param>
        /// <param name="expression">The expression.</param>
        protected override void WriteCondition(XmlWriter writer, XacmlExpression expression) {
            Contract.Requires<ArgumentNullException>(writer != null);
            Contract.Requires<ArgumentNullException>(expression != null);

            writer.WriteStartElement(XacmlConstants.Prefixes.Policy, XacmlConstants.ElementNames.Condition, this.version.NamespacePolicy);
            this.WriteExpressionType(writer, expression);
            writer.WriteEndElement();
        }