235 lines
11 KiB
C#
235 lines
11 KiB
C#
using System;
|
|
using System.Activities.Expressions;
|
|
using System.Activities.Presentation.Expressions;
|
|
using System.Activities.Presentation.Internal.PropertyEditing;
|
|
using System.Activities.Presentation.Model;
|
|
using System.Activities.Presentation.View;
|
|
using System.Activities.XamlIntegration;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Runtime;
|
|
using System.Runtime.Versioning;
|
|
using System.Text;
|
|
using Microsoft.Activities.Presentation;
|
|
using Microsoft.VisualBasic.Activities;
|
|
|
|
namespace System.Activities.Presentation
|
|
{
|
|
internal static class ExpressionHelper
|
|
{
|
|
internal static string GetExpressionString(Activity expression)
|
|
{
|
|
return ExpressionHelper.GetExpressionString(expression, null as ParserContext);
|
|
}
|
|
|
|
internal static string GetExpressionString(Activity expression, ModelItem owner)
|
|
{
|
|
ParserContext context = new ParserContext(owner);
|
|
return ExpressionHelper.GetExpressionString(expression, context);
|
|
}
|
|
|
|
internal static string GetExpressionString(Activity expression, ParserContext context)
|
|
{
|
|
string expressionString = null;
|
|
if (expression != null)
|
|
{
|
|
Type expressionType = expression.GetType();
|
|
Type expressionArgumentType = expressionType.IsGenericType ? expressionType.GetGenericArguments()[0] : typeof(object);
|
|
bool isLiteral = expressionType.IsGenericType ? Type.Equals(typeof(Literal<>), expressionType.GetGenericTypeDefinition()) : false;
|
|
|
|
//handle ITextExpression
|
|
if (expression is ITextExpression)
|
|
{
|
|
ITextExpression textExpression = expression as ITextExpression;
|
|
expressionString = textExpression.ExpressionText;
|
|
}
|
|
//handle Literal Expression
|
|
else if (isLiteral)
|
|
{
|
|
TypeConverter converter = XamlUtilities.GetConverter(expressionArgumentType);
|
|
if (converter != null && converter.CanConvertTo(context, typeof(string)))
|
|
{
|
|
PropertyInfo literalValueProperty = expressionType.GetProperty("Value");
|
|
Fx.Assert(literalValueProperty != null && literalValueProperty.GetGetMethod() != null, "Literal<T> must have the Value property with a public get accessor.");
|
|
object literalValue = literalValueProperty.GetValue(expression, null);
|
|
string convertedString = null;
|
|
if (literalValue != null)
|
|
{
|
|
try
|
|
{
|
|
convertedString = converter.ConvertToString(context, literalValue);
|
|
}
|
|
catch (ArgumentException)
|
|
{
|
|
convertedString = literalValue.ToString();
|
|
}
|
|
}
|
|
expressionString = expressionArgumentType == typeof(string) ? ("\"" + convertedString + "\"") : convertedString;
|
|
}
|
|
}
|
|
else if (expressionType.IsGenericType &&
|
|
(expressionType.GetGenericTypeDefinition() == typeof(VariableValue<>) ||
|
|
expressionType.GetGenericTypeDefinition() == typeof(VariableReference<>)))
|
|
{
|
|
PropertyInfo variableProperty = expression.GetType().GetProperty("Variable");
|
|
Variable variable = variableProperty.GetValue(expression, null) as Variable;
|
|
if (variable != null)
|
|
{
|
|
expressionString = variable.Name;
|
|
}
|
|
}
|
|
}
|
|
|
|
return expressionString;
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
|
|
Justification = "The conversion to an expression might fail due to invalid user input. Propagating exceptions might lead to VS crash.")]
|
|
[SuppressMessage("Reliability", "Reliability108:IsFatalRule",
|
|
Justification = "The conversion to an expression might fail due to invalid user input. Propagating exceptions might lead to VS crash.")]
|
|
internal static ActivityWithResult TryCreateLiteral(Type type, string expressionText, ParserContext context)
|
|
{
|
|
//try easy way first - look if there is a type conversion which supports conversion between expression type and string
|
|
TypeConverter literalValueConverter = null;
|
|
bool isQuotedString = false;
|
|
if (CanTypeBeSerializedAsLiteral(type))
|
|
{
|
|
bool shouldBeQuoted = typeof(string) == type;
|
|
|
|
//whether string begins and ends with quotes '"'. also, if there are
|
|
//more quotes within than those begining and ending ones, do not bother with literal - assume this is an expression.
|
|
isQuotedString = shouldBeQuoted &&
|
|
expressionText.StartsWith("\"", StringComparison.CurrentCulture) &&
|
|
expressionText.EndsWith("\"", StringComparison.CurrentCulture) &&
|
|
expressionText.IndexOf("\"", 1, StringComparison.CurrentCulture) == expressionText.Length - 1;
|
|
|
|
//if expression is a string, we must ensure it is quoted, in case of other types - just get the converter
|
|
if ((shouldBeQuoted && isQuotedString) || !shouldBeQuoted)
|
|
{
|
|
literalValueConverter = TypeDescriptor.GetConverter(type);
|
|
}
|
|
}
|
|
|
|
//if there is converter - try to convert
|
|
if (null != literalValueConverter && literalValueConverter.CanConvertFrom(context, typeof(string)))
|
|
{
|
|
try
|
|
{
|
|
var valueToConvert = isQuotedString ? expressionText.Substring(1, expressionText.Length - 2) : expressionText;
|
|
var converterValue = literalValueConverter.ConvertFrom(context, CultureInfo.CurrentCulture, valueToConvert);
|
|
//ok, succeeded - create literal of given type
|
|
var concreteExpType = typeof(Literal<>).MakeGenericType(type);
|
|
return (ActivityWithResult)Activator.CreateInstance(concreteExpType, converterValue);
|
|
}
|
|
//conversion failed - do nothing, let VB compiler take care of the expression
|
|
catch { }
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
internal static bool CanTypeBeSerializedAsLiteral(Type type)
|
|
{
|
|
//type must be set and cannot be object
|
|
if (null == type || typeof(object) == type)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return type.IsPrimitive || type == typeof(string) || type == typeof(TimeSpan) || type == typeof(DateTime);
|
|
}
|
|
|
|
// Test whether this activity is Expression
|
|
internal static bool IsExpression(this Activity activity)
|
|
{
|
|
return activity is ActivityWithResult;
|
|
}
|
|
|
|
internal static bool IsGenericLocationExpressionType(ActivityWithResult expression)
|
|
{
|
|
Type expressionType = expression.ResultType;
|
|
return expressionType.IsGenericType && typeof(Location<>) == expressionType.GetGenericTypeDefinition();
|
|
}
|
|
|
|
internal static bool TryMorphExpression(ActivityWithResult originalExpression, bool isLocation, Type targetType,
|
|
EditingContext context, out ActivityWithResult morphedExpression)
|
|
{
|
|
bool succeeded = false;
|
|
morphedExpression = null;
|
|
if (originalExpression != null)
|
|
{
|
|
Type resultType = originalExpression.ResultType;
|
|
if ((isLocation) && (ExpressionHelper.IsGenericLocationExpressionType(originalExpression) && (targetType == resultType.GetGenericArguments()[0])) ||
|
|
(!isLocation) && (resultType == targetType))
|
|
{
|
|
//no need to morph
|
|
succeeded = true;
|
|
morphedExpression = originalExpression;
|
|
}
|
|
else
|
|
{
|
|
Type expressionType = originalExpression.GetType();
|
|
if (expressionType.IsGenericType)
|
|
{
|
|
expressionType = expressionType.GetGenericTypeDefinition();
|
|
}
|
|
|
|
ExpressionMorphHelperAttribute morphHelperAttribute = ExtensibilityAccessor.GetAttribute<ExpressionMorphHelperAttribute>(expressionType);
|
|
if (morphHelperAttribute != null)
|
|
{
|
|
ExpressionMorphHelper morphHelper = Activator.CreateInstance(morphHelperAttribute.ExpressionMorphHelperType) as ExpressionMorphHelper;
|
|
if (morphHelper != null)
|
|
{
|
|
succeeded = morphHelper.TryMorphExpression(originalExpression, isLocation, targetType, context, out morphedExpression);
|
|
if (succeeded && morphedExpression != null)
|
|
{
|
|
string editorName = ExpressionActivityEditor.GetExpressionActivityEditor(originalExpression);
|
|
if (!string.IsNullOrWhiteSpace(editorName))
|
|
{
|
|
ExpressionActivityEditor.SetExpressionActivityEditor(morphedExpression, editorName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
succeeded = true;
|
|
}
|
|
return succeeded;
|
|
}
|
|
|
|
// this method may has side effect, it may modify model.
|
|
internal static bool TryInferReturnType(ActivityWithResult expression, EditingContext context, out Type returnType)
|
|
{
|
|
bool succeeded = false;
|
|
returnType = null;
|
|
Type expressionType = expression.GetType();
|
|
if (expressionType.IsGenericType)
|
|
{
|
|
expressionType = expressionType.GetGenericTypeDefinition();
|
|
ExpressionMorphHelperAttribute morphHelperAttribute = ExtensibilityAccessor.GetAttribute<ExpressionMorphHelperAttribute>(expressionType);
|
|
if (morphHelperAttribute != null)
|
|
{
|
|
ExpressionMorphHelper morphHelper = Activator.CreateInstance(morphHelperAttribute.ExpressionMorphHelperType) as ExpressionMorphHelper;
|
|
if (morphHelper != null)
|
|
{
|
|
succeeded = morphHelper.TryInferReturnType(expression, context, out returnType);
|
|
}
|
|
}
|
|
}
|
|
return succeeded;
|
|
}
|
|
|
|
internal static string GetRootEditorSetting(ModelTreeManager modelTreeManager, FrameworkName targetFramework)
|
|
{
|
|
return ExpressionSettingHelper.GetRootEditorSetting(modelTreeManager, targetFramework);
|
|
}
|
|
}
|
|
}
|