328 lines
12 KiB
C#
328 lines
12 KiB
C#
|
//-----------------------------------------------------------------------------
|
|||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
|
|||
|
namespace System.Activities.XamlIntegration
|
|||
|
{
|
|||
|
using System;
|
|||
|
using System.Activities;
|
|||
|
using System.Activities.Expressions;
|
|||
|
using System.Activities.Runtime;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Diagnostics.CodeAnalysis;
|
|||
|
using System.Linq.Expressions;
|
|||
|
using System.Runtime;
|
|||
|
|
|||
|
public abstract class CompiledDataContext
|
|||
|
{
|
|||
|
IList<Location> locations;
|
|||
|
IList<LocationReference> locationReferences;
|
|||
|
ExpressionTreeRewriter visitor;
|
|||
|
|
|||
|
[SuppressMessage(FxCop.Category.Usage, FxCop.Rule.DoNotCallOverridableMethodsInConstructors, Justification = "Derived classes are always generated code")]
|
|||
|
protected CompiledDataContext(IList<LocationReference> locationReferences, ActivityContext activityContext)
|
|||
|
{
|
|||
|
this.locationReferences = locationReferences;
|
|||
|
|
|||
|
if (this.locationReferences == null)
|
|||
|
{
|
|||
|
this.locationReferences = new List<LocationReference>();
|
|||
|
}
|
|||
|
|
|||
|
this.locations = ConvertReferences(this.locationReferences, activityContext);
|
|||
|
}
|
|||
|
|
|||
|
protected CompiledDataContext(IList<Location> locations)
|
|||
|
{
|
|||
|
this.locations = locations;
|
|||
|
}
|
|||
|
|
|||
|
protected CompiledDataContext(IList<LocationReference> locationReferences)
|
|||
|
{
|
|||
|
this.visitor = new ExpressionTreeRewriter(locationReferences);
|
|||
|
}
|
|||
|
|
|||
|
protected object GetVariableValue(int index)
|
|||
|
{
|
|||
|
return this.locations[index].Value;
|
|||
|
}
|
|||
|
|
|||
|
protected void SetVariableValue(int index, object value)
|
|||
|
{
|
|||
|
this.locations[index].Value = value;
|
|||
|
}
|
|||
|
|
|||
|
protected virtual void GetValueTypeValues()
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
protected virtual void SetValueTypeValues()
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
protected Expression RewriteExpressionTree(Expression originalExpression)
|
|||
|
{
|
|||
|
LambdaExpression lambdaExpression = originalExpression as LambdaExpression;
|
|||
|
|
|||
|
if (lambdaExpression == null)
|
|||
|
{
|
|||
|
throw FxTrace.Exception.Argument("originalExpression", SR.LambdaExpressionTypeRequired);
|
|||
|
}
|
|||
|
|
|||
|
if (lambdaExpression.ReturnType == null || lambdaExpression.ReturnType == typeof(void))
|
|||
|
{
|
|||
|
throw FxTrace.Exception.Argument("originalExpression", SR.LambdaExpressionReturnTypeInvalid);
|
|||
|
}
|
|||
|
|
|||
|
return this.visitor.Visit(Expression.Lambda(
|
|||
|
typeof(Func<,>).MakeGenericType(typeof(ActivityContext), lambdaExpression.ReturnType),
|
|||
|
lambdaExpression.Body,
|
|||
|
new ParameterExpression[] { ExpressionUtilities.RuntimeContextParameter }));
|
|||
|
}
|
|||
|
|
|||
|
public Location<T> GetLocation<T>(Func<T> getMethod, Action<T> setMethod, int expressionId, Activity compiledRootActivity, ActivityContext activityContext)
|
|||
|
{
|
|||
|
return new CompiledLocation<T>(getMethod, setMethod, this.locationReferences, this.locations, expressionId, compiledRootActivity, activityContext);
|
|||
|
}
|
|||
|
|
|||
|
public Location<T> GetLocation<T>(Func<T> getMethod, Action<T> setMethod)
|
|||
|
{
|
|||
|
return new CompiledLocation<T>(getMethod, setMethod);
|
|||
|
}
|
|||
|
|
|||
|
protected static object GetDataContextActivities(Activity compiledRoot, bool forImplementation)
|
|||
|
{
|
|||
|
CompiledDataContextActivityVistor vistor = new CompiledDataContextActivityVistor();
|
|||
|
vistor.Visit(compiledRoot, forImplementation);
|
|||
|
CompiledDataContextActivitiesCache cache = new CompiledDataContextActivitiesCache(vistor.DataContextActivities);
|
|||
|
return cache;
|
|||
|
}
|
|||
|
|
|||
|
protected static CompiledDataContext[] GetCompiledDataContextCache(object dataContextActivities, ActivityContext activityContext, Activity compiledRoot, bool forImplementation, int compiledDataContextCount)
|
|||
|
{
|
|||
|
ActivityInstance cacheInstance = GetDataContextInstance((CompiledDataContextActivitiesCache)dataContextActivities, activityContext, compiledRoot);
|
|||
|
|
|||
|
HybridDictionary<Activity, CompiledDataContext[]> cache = null;
|
|||
|
if (forImplementation)
|
|||
|
{
|
|||
|
cache = (HybridDictionary<Activity, CompiledDataContext[]>)cacheInstance.CompiledDataContextsForImplementation;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
cache = (HybridDictionary<Activity, CompiledDataContext[]>)cacheInstance.CompiledDataContexts;
|
|||
|
}
|
|||
|
|
|||
|
if (cache == null)
|
|||
|
{
|
|||
|
cache = new HybridDictionary<Activity, CompiledDataContext[]>();
|
|||
|
|
|||
|
if (forImplementation)
|
|||
|
{
|
|||
|
cacheInstance.CompiledDataContextsForImplementation = cache;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
cacheInstance.CompiledDataContexts = cache;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
CompiledDataContext[] result = null;
|
|||
|
if (!cache.TryGetValue(compiledRoot, out result))
|
|||
|
{
|
|||
|
result = new CompiledDataContext[compiledDataContextCount];
|
|||
|
cache.Add(compiledRoot, result);
|
|||
|
}
|
|||
|
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
static ActivityInstance GetDataContextInstance(CompiledDataContextActivitiesCache dataContextActivities, ActivityContext activityContext, Activity compiledRoot)
|
|||
|
{
|
|||
|
ActivityInstance dataContextInstance = null;
|
|||
|
|
|||
|
ActivityInstance currentInstance = activityContext.CurrentInstance;
|
|||
|
|
|||
|
while (currentInstance != null)
|
|||
|
{
|
|||
|
if (dataContextActivities.Contains(currentInstance.Activity))
|
|||
|
{
|
|||
|
dataContextInstance = currentInstance;
|
|||
|
break;
|
|||
|
}
|
|||
|
//
|
|||
|
// Make sure we don't walk out of our IdSpace
|
|||
|
if (currentInstance.Activity == compiledRoot)
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
//
|
|||
|
// For SecondaryRoot scenarios the ActivityInstance tree may not
|
|||
|
// contain any of the data context activity instances because
|
|||
|
// the instance tree does not have to match the activity definition tree.
|
|||
|
// In this case just use the root instance.
|
|||
|
if (currentInstance.Parent == null)
|
|||
|
{
|
|||
|
dataContextInstance = currentInstance;
|
|||
|
}
|
|||
|
|
|||
|
currentInstance = currentInstance.Parent;
|
|||
|
}
|
|||
|
|
|||
|
if (dataContextInstance == null)
|
|||
|
{
|
|||
|
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.CompiledExpressionsNoCompiledRoot(activityContext.Activity.Id)));
|
|||
|
}
|
|||
|
|
|||
|
return dataContextInstance;
|
|||
|
}
|
|||
|
|
|||
|
IList<Location> ConvertReferences(IList<LocationReference> locationReferences, ActivityContext activityContext)
|
|||
|
{
|
|||
|
IList<Location> temp = new List<Location>(locationReferences.Count);
|
|||
|
|
|||
|
foreach (LocationReference reference in locationReferences)
|
|||
|
{
|
|||
|
temp.Add(reference.GetLocation(activityContext));
|
|||
|
}
|
|||
|
|
|||
|
return temp;
|
|||
|
}
|
|||
|
|
|||
|
class CompiledDataContextActivitiesCache
|
|||
|
{
|
|||
|
bool optimized;
|
|||
|
HashSet<Activity> activities;
|
|||
|
|
|||
|
Activity activity0;
|
|||
|
Activity activity1;
|
|||
|
Activity activity2;
|
|||
|
Activity activity3;
|
|||
|
Activity activity4;
|
|||
|
|
|||
|
public CompiledDataContextActivitiesCache(HashSet<Activity> dataContextActivities)
|
|||
|
{
|
|||
|
this.activities = dataContextActivities;
|
|||
|
|
|||
|
if (this.activities != null && this.activities.Count <= 5)
|
|||
|
{
|
|||
|
Activity[] activitiesArray = new Activity[5];
|
|||
|
this.activities.CopyTo(activitiesArray);
|
|||
|
|
|||
|
activity0 = activitiesArray[0];
|
|||
|
activity1 = activitiesArray[1];
|
|||
|
activity2 = activitiesArray[2];
|
|||
|
activity3 = activitiesArray[3];
|
|||
|
activity4 = activitiesArray[4];
|
|||
|
|
|||
|
this.optimized = true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public bool Contains(Activity target)
|
|||
|
{
|
|||
|
if (this.optimized)
|
|||
|
{
|
|||
|
if (this.activity0 == target)
|
|||
|
{
|
|||
|
return true;
|
|||
|
}
|
|||
|
else if (this.activity1 == target)
|
|||
|
{
|
|||
|
return true;
|
|||
|
}
|
|||
|
else if (this.activity2 == target)
|
|||
|
{
|
|||
|
return true;
|
|||
|
}
|
|||
|
else if (this.activity3 == target)
|
|||
|
{
|
|||
|
return true;
|
|||
|
}
|
|||
|
else if (this.activity4 == target)
|
|||
|
{
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return this.activities.Contains(target);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
class CompiledDataContextActivityVistor : CompiledExpressionActivityVisitor
|
|||
|
{
|
|||
|
HashSet<Activity> dataContextActivities;
|
|||
|
bool inVariableScopeArgument;
|
|||
|
|
|||
|
public CompiledDataContextActivityVistor()
|
|||
|
{
|
|||
|
this.dataContextActivities = new HashSet<Activity>(new ReferenceComparer<Activity>());
|
|||
|
}
|
|||
|
|
|||
|
public HashSet<Activity> DataContextActivities
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return this.dataContextActivities;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
protected override void VisitRoot(Activity activity, out bool exit)
|
|||
|
{
|
|||
|
this.dataContextActivities.Add(activity);
|
|||
|
base.VisitRoot(activity, out exit);
|
|||
|
}
|
|||
|
|
|||
|
protected override void VisitVariableScope(Activity activity, out bool exit)
|
|||
|
{
|
|||
|
if (!this.dataContextActivities.Contains(activity))
|
|||
|
{
|
|||
|
this.dataContextActivities.Add(activity);
|
|||
|
}
|
|||
|
base.VisitVariableScope(activity, out exit);
|
|||
|
}
|
|||
|
|
|||
|
protected override void VisitDelegate(ActivityDelegate activityDelegate, out bool exit)
|
|||
|
{
|
|||
|
if (activityDelegate.Handler != null)
|
|||
|
{
|
|||
|
this.dataContextActivities.Add(activityDelegate.Handler);
|
|||
|
}
|
|||
|
base.VisitDelegate(activityDelegate, out exit);
|
|||
|
}
|
|||
|
|
|||
|
protected override void VisitVariableScopeArgument(RuntimeArgument runtimeArgument, out bool exit)
|
|||
|
{
|
|||
|
this.inVariableScopeArgument = true;
|
|||
|
base.VisitVariableScopeArgument(runtimeArgument, out exit);
|
|||
|
this.inVariableScopeArgument = false;
|
|||
|
}
|
|||
|
|
|||
|
protected override void VisitITextExpression(Activity activity, out bool exit)
|
|||
|
{
|
|||
|
if (this.inVariableScopeArgument)
|
|||
|
{
|
|||
|
this.dataContextActivities.Add(activity);
|
|||
|
}
|
|||
|
base.VisitITextExpression(activity, out exit);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
class ReferenceComparer<T> : IEqualityComparer<T>
|
|||
|
{
|
|||
|
bool IEqualityComparer<T>.Equals(T x, T y)
|
|||
|
{
|
|||
|
return object.ReferenceEquals(x, y);
|
|||
|
}
|
|||
|
|
|||
|
int IEqualityComparer<T>.GetHashCode(T target)
|
|||
|
{
|
|||
|
return target.GetHashCode();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|