e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
345 lines
11 KiB
C#
345 lines
11 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
namespace System.Activities
|
|
{
|
|
using System;
|
|
using System.Activities.Runtime;
|
|
using System.Activities.Validation;
|
|
using System.Activities.XamlIntegration;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Runtime;
|
|
using System.Runtime.Serialization;
|
|
using System.Windows.Markup;
|
|
|
|
public abstract class Argument
|
|
{
|
|
public static readonly int UnspecifiedEvaluationOrder = -1;
|
|
|
|
public const string ResultValue = "Result";
|
|
|
|
ArgumentDirection direction;
|
|
RuntimeArgument runtimeArgument;
|
|
int evaluationOrder;
|
|
|
|
internal Argument()
|
|
{
|
|
this.evaluationOrder = Argument.UnspecifiedEvaluationOrder;
|
|
}
|
|
|
|
public Type ArgumentType
|
|
{
|
|
get;
|
|
internal set;
|
|
}
|
|
|
|
public ArgumentDirection Direction
|
|
{
|
|
get
|
|
{
|
|
return this.direction;
|
|
}
|
|
internal set
|
|
{
|
|
ArgumentDirectionHelper.Validate(value, "value");
|
|
this.direction = value;
|
|
}
|
|
}
|
|
|
|
[DefaultValue(-1)]
|
|
public int EvaluationOrder
|
|
{
|
|
get
|
|
{
|
|
return this.evaluationOrder;
|
|
}
|
|
set
|
|
{
|
|
if (value < 0 && value != Argument.UnspecifiedEvaluationOrder)
|
|
{
|
|
throw FxTrace.Exception.ArgumentOutOfRange("EvaluationOrder", value, SR.InvalidEvaluationOrderValue);
|
|
}
|
|
this.evaluationOrder = value;
|
|
}
|
|
}
|
|
|
|
[IgnoreDataMember] // this member is repeated by all subclasses, which we control
|
|
[DefaultValue(null)]
|
|
public ActivityWithResult Expression
|
|
{
|
|
get
|
|
{
|
|
return this.ExpressionCore;
|
|
}
|
|
set
|
|
{
|
|
this.ExpressionCore = value;
|
|
}
|
|
}
|
|
|
|
internal abstract ActivityWithResult ExpressionCore
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
internal RuntimeArgument RuntimeArgument
|
|
{
|
|
get
|
|
{
|
|
return this.runtimeArgument;
|
|
}
|
|
set
|
|
{
|
|
this.runtimeArgument = value;
|
|
}
|
|
}
|
|
|
|
internal bool IsInTree
|
|
{
|
|
get
|
|
{
|
|
return (this.runtimeArgument != null && this.runtimeArgument.IsInTree);
|
|
}
|
|
}
|
|
|
|
internal bool WasDesignTimeNull
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
internal int Id
|
|
{
|
|
get
|
|
{
|
|
Fx.Assert(this.runtimeArgument != null, "We shouldn't call Id unless we have a runtime argument.");
|
|
return this.runtimeArgument.Id;
|
|
}
|
|
}
|
|
|
|
internal bool IsEmpty
|
|
{
|
|
get
|
|
{
|
|
return this.Expression == null;
|
|
}
|
|
}
|
|
|
|
public static Argument CreateReference(Argument argumentToReference, string referencedArgumentName)
|
|
{
|
|
if (argumentToReference == null)
|
|
{
|
|
throw FxTrace.Exception.ArgumentNull("argumentToReference");
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(referencedArgumentName))
|
|
{
|
|
throw FxTrace.Exception.ArgumentNullOrEmpty("referencedArgumentName");
|
|
}
|
|
|
|
return ActivityUtilities.CreateReferenceArgument(argumentToReference.ArgumentType, argumentToReference.Direction, referencedArgumentName);
|
|
}
|
|
|
|
// for ArgumentValueSerializer
|
|
internal bool CanConvertToString(IValueSerializerContext context)
|
|
{
|
|
if (this.WasDesignTimeNull)
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if (this.EvaluationOrder == Argument.UnspecifiedEvaluationOrder)
|
|
{
|
|
return ActivityWithResultValueSerializer.CanConvertToStringWrapper(this.Expression, context);
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal string ConvertToString(IValueSerializerContext context)
|
|
{
|
|
if (this.WasDesignTimeNull)
|
|
{
|
|
// this argument instance was artificially created by the runtime
|
|
// to Xaml, this should appear as {x:Null}
|
|
return null;
|
|
}
|
|
|
|
return ActivityWithResultValueSerializer.ConvertToStringWrapper(this.Expression, context);
|
|
}
|
|
|
|
internal static void Bind(Argument binding, RuntimeArgument argument)
|
|
{
|
|
if (binding != null)
|
|
{
|
|
Fx.Assert(binding.Direction == argument.Direction, "The directions must match.");
|
|
Fx.Assert(binding.ArgumentType == argument.Type, "The types must match.");
|
|
|
|
binding.RuntimeArgument = argument;
|
|
}
|
|
|
|
argument.BoundArgument = binding;
|
|
}
|
|
|
|
internal static void TryBind(Argument binding, RuntimeArgument argument, Activity violationOwner)
|
|
{
|
|
if (argument == null)
|
|
{
|
|
throw FxTrace.Exception.ArgumentNull("argument");
|
|
}
|
|
|
|
bool passedValidations = true;
|
|
|
|
if (binding != null)
|
|
{
|
|
if (binding.Direction != argument.Direction)
|
|
{
|
|
violationOwner.AddTempValidationError(new ValidationError(SR.ArgumentDirectionMismatch(argument.Name, argument.Direction, binding.Direction)));
|
|
passedValidations = false;
|
|
}
|
|
|
|
if (binding.ArgumentType != argument.Type)
|
|
{
|
|
violationOwner.AddTempValidationError(new ValidationError(SR.ArgumentTypeMismatch(argument.Name, argument.Type, binding.ArgumentType)));
|
|
passedValidations = false;
|
|
}
|
|
}
|
|
|
|
if (passedValidations)
|
|
{
|
|
Bind(binding, argument);
|
|
}
|
|
}
|
|
|
|
public static Argument Create(Type type, ArgumentDirection direction)
|
|
{
|
|
return ActivityUtilities.CreateArgument(type, direction);
|
|
}
|
|
|
|
internal abstract Location CreateDefaultLocation();
|
|
|
|
internal abstract void Declare(LocationEnvironment targetEnvironment, ActivityInstance activityInstance);
|
|
|
|
// Soft-Link: This method is referenced through reflection by
|
|
// ExpressionUtilities.TryRewriteLambdaExpression. Update that
|
|
// file if the signature changes.
|
|
public object Get(ActivityContext context)
|
|
{
|
|
return Get<object>(context);
|
|
}
|
|
|
|
// Soft-Link: This method is referenced through reflection by
|
|
// ExpressionUtilities.TryRewriteLambdaExpression. Update that
|
|
// file if the signature changes.
|
|
public T Get<T>(ActivityContext context)
|
|
{
|
|
if (context == null)
|
|
{
|
|
throw FxTrace.Exception.ArgumentNull("context");
|
|
}
|
|
|
|
ThrowIfNotInTree();
|
|
|
|
return context.GetValue<T>(this.RuntimeArgument);
|
|
}
|
|
|
|
public void Set(ActivityContext context, object value)
|
|
{
|
|
if (context == null)
|
|
{
|
|
throw FxTrace.Exception.ArgumentNull("context");
|
|
}
|
|
|
|
ThrowIfNotInTree();
|
|
|
|
context.SetValue(this.RuntimeArgument, value);
|
|
}
|
|
|
|
internal void Validate(Activity owner, ref IList<ValidationError> validationErrors)
|
|
{
|
|
if (this.Expression != null)
|
|
{
|
|
if (this.Expression.Result != null && !this.Expression.Result.IsEmpty)
|
|
{
|
|
ValidationError validationError = new ValidationError(SR.ResultCannotBeSetOnArgumentExpressions, false, this.RuntimeArgument.Name, owner);
|
|
ActivityUtilities.Add(ref validationErrors, validationError);
|
|
}
|
|
|
|
ActivityWithResult actualExpression = this.Expression;
|
|
|
|
if (actualExpression is IExpressionWrapper)
|
|
{
|
|
actualExpression = ((IExpressionWrapper)actualExpression).InnerExpression;
|
|
}
|
|
|
|
switch (this.Direction)
|
|
{
|
|
case ArgumentDirection.In:
|
|
if (actualExpression.ResultType != this.ArgumentType)
|
|
{
|
|
ActivityUtilities.Add(
|
|
ref validationErrors,
|
|
new ValidationError(SR.ArgumentValueExpressionTypeMismatch(this.ArgumentType, actualExpression.ResultType), false, this.RuntimeArgument.Name, owner));
|
|
}
|
|
break;
|
|
case ArgumentDirection.InOut:
|
|
case ArgumentDirection.Out:
|
|
Type locationType;
|
|
if (!ActivityUtilities.IsLocationGenericType(actualExpression.ResultType, out locationType) ||
|
|
locationType != this.ArgumentType)
|
|
{
|
|
Type expectedType = ActivityUtilities.CreateActivityWithResult(ActivityUtilities.CreateLocation(this.ArgumentType));
|
|
ActivityUtilities.Add(
|
|
ref validationErrors,
|
|
new ValidationError(SR.ArgumentLocationExpressionTypeMismatch(expectedType.FullName, actualExpression.GetType().FullName), false, this.RuntimeArgument.Name, owner));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// optional "fast-path" for arguments that can be resolved synchronously
|
|
internal abstract bool TryPopulateValue(LocationEnvironment targetEnvironment, ActivityInstance targetActivityInstance, ActivityExecutor executor);
|
|
|
|
// Soft-Link: This method is referenced through reflection by
|
|
// ExpressionUtilities.TryRewriteLambdaExpression. Update that
|
|
// file if the signature changes.
|
|
public Location GetLocation(ActivityContext context)
|
|
{
|
|
if (context == null)
|
|
{
|
|
throw FxTrace.Exception.ArgumentNull("context");
|
|
}
|
|
|
|
ThrowIfNotInTree();
|
|
|
|
return this.runtimeArgument.GetLocation(context);
|
|
}
|
|
|
|
internal void ThrowIfNotInTree()
|
|
{
|
|
if (!this.IsInTree)
|
|
{
|
|
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.ArgumentNotInTree(this.ArgumentType)));
|
|
}
|
|
}
|
|
|
|
internal static Location<T> CreateLocation<T>()
|
|
{
|
|
return new Location<T>();
|
|
}
|
|
|
|
internal interface IExpressionWrapper
|
|
{
|
|
ActivityWithResult InnerExpression { get; }
|
|
}
|
|
}
|
|
}
|