Code:
/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / Designer / CompMod / System / ComponentModel / Design / Serialization / CodeDomSerializerBase.cs / 3 / CodeDomSerializerBase.cs
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//-----------------------------------------------------------------------------
namespace System.ComponentModel.Design.Serialization {
using System;
using System.Design;
using System.Resources;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection;
using System.Text;
///
///
/// This base class is used as a shared base between CodeDomSerializer and TypeCodeDomSerializer.
/// It is not meant to be publicly derived from.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public abstract class CodeDomSerializerBase {
private static readonly Attribute[] runTimeProperties = new Attribute[] { DesignOnlyAttribute.No };
private static readonly CodeThisReferenceExpression thisRef = new CodeThisReferenceExpression();
private static TraceSwitch traceSerialization = new TraceSwitch("DesignerSerialization", "Trace design time serialization");
private static Stack traceScope;
///
/// Internal constructor so only we can derive from this class.
///
internal CodeDomSerializerBase() {
}
///
///
/// This method is invoked during deserialization to obtain an instance of an object. When this is called, an instance
/// of the requested type should be returned. The default implementation invokes manager.CreateInstance.
///
protected virtual object DeserializeInstance(IDesignerSerializationManager manager, Type type, object[] parameters, string name, bool addToContainer) {
if (manager == null) throw new ArgumentNullException("manager");
if (type == null) throw new ArgumentNullException("type");
return manager.CreateInstance(type, parameters, name, addToContainer);
}
///
/// This routine returns the correct typename given a CodeTypeReference. It expands the child typenames
/// and builds up the clr formatted generic name. If its not a generic, it just returns BaseType.
///
internal static string GetTypeNameFromCodeTypeReference(IDesignerSerializationManager manager, CodeTypeReference typeref) {
//we do this to avoid an extra gettype for the usual nongeneric case.
if (typeref.TypeArguments == null || typeref.TypeArguments.Count == 0) {
return typeref.BaseType;
}
return GetTypeNameFromCodeTypeReferenceHelper(manager, typeref);
}
///
/// This helper is used by GetTypeNameFromCodeTypeReference -- do not call this directly.
///
private static string GetTypeNameFromCodeTypeReferenceHelper(IDesignerSerializationManager manager, CodeTypeReference typeref) {
if (typeref.TypeArguments == null || typeref.TypeArguments.Count == 0) {
Type t = manager.GetType(typeref.BaseType);
//we use the assemblyqualifiedname where we can so that GetType will find it correctly.
if (t != null) {
return t.AssemblyQualifiedName;
}
return typeref.BaseType;
}
//create the MyGeneric`2[ part
StringBuilder typename = new StringBuilder(typeref.BaseType);
if (!typeref.BaseType.Contains("`")) {
typename.Append("`");
typename.Append(typeref.TypeArguments.Count);
}
typename.Append("[");
bool first = true;
//now create each sub-argument part.
foreach (CodeTypeReference childref in typeref.TypeArguments) {
if (!first) {
typename.Append(",");
}
typename.Append("[");
typename.Append(GetTypeNameFromCodeTypeReferenceHelper(manager, childref));
typename.Append("]");
first = false;
}
typename.Append("]");
//otherwise, we have a generic and we need to format it.
return typename.ToString();
}
[SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
private object DeserializePropertyReferenceExpression(IDesignerSerializationManager manager, CodePropertyReferenceExpression propertyReferenceEx, bool reportError) {
object result = propertyReferenceEx;
Trace("Property reference : {0}", propertyReferenceEx.PropertyName);
object target = DeserializeExpression(manager, null, propertyReferenceEx.TargetObject);
if (target != null && !(target is CodeExpression)) {
// if it's a type, then we've got ourselves a static field...
//
if (!(target is Type)) {
PropertyDescriptor prop = TypeDescriptor.GetProperties(target)[propertyReferenceEx.PropertyName];
if (prop != null) {
result = prop.GetValue(target);
}
else {
// This could be a protected property on the base class. Make sure we're
// actually accessing through the base class, and then get the property
// directly from reflection.
//
if (GetExpression(manager, target) is CodeThisReferenceExpression) {
PropertyInfo propInfo = TypeDescriptor.GetReflectionType(target).GetProperty(propertyReferenceEx.PropertyName, BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (propInfo != null) {
result = propInfo.GetValue(target, null);
}
}
}
}
else {
PropertyInfo prop = TypeDescriptor.GetReflectionType((Type)target).GetProperty(propertyReferenceEx.PropertyName, BindingFlags.GetProperty | BindingFlags.Static | BindingFlags.Public);
if (prop != null) {
result = prop.GetValue(null, null);
}
}
if (result == propertyReferenceEx && reportError) {
string typeName = (target is Type) ? ((Type)target).FullName : TypeDescriptor.GetReflectionType(target).FullName;
Error(manager, SR.GetString(SR.SerializerNoSuchProperty, typeName, propertyReferenceEx.PropertyName), SR.SerializerNoSuchProperty);
}
}
TraceWarningIf(result == propertyReferenceEx, "Could not resolve property {0} to an object instance.", propertyReferenceEx.PropertyName);
return result;
}
///
///
/// This is a helper method that will deserialize a given expression. It deserializes
/// the statement by interpreting and executing the CodeDom expression, returning
/// the results.
///
[SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")]
[SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
protected object DeserializeExpression(IDesignerSerializationManager manager, string name, CodeExpression expression) {
object result = expression;
using (TraceScope("CodeDomSerializerBase::DeserializeExpression")) {
// Perf: is -> as changes, change ordering based on possibility of occurance
// If you are adding to this, use as instead of is + cast and order new expressions
// in order of frequency in typical user code.
CodePrimitiveExpression primitiveEx;
CodePropertyReferenceExpression propertyReferenceEx;
CodeTypeReferenceExpression typeReferenceEx;
CodeObjectCreateExpression objectCreateEx;
CodeArgumentReferenceExpression argumentReferenceEx;
CodeFieldReferenceExpression fieldReferenceEx;
CodeMethodInvokeExpression methodInvokeEx;
CodeVariableReferenceExpression variableReferenceEx;
CodeCastExpression castEx;
CodeArrayCreateExpression arrayCreateEx;
CodeArrayIndexerExpression arrayIndexerEx;
CodeBinaryOperatorExpression binaryOperatorEx;
CodeDelegateInvokeExpression delegateInvokeEx;
CodeDirectionExpression directionEx;
CodeIndexerExpression indexerEx;
CodeParameterDeclarationExpression parameterDeclaration;
CodeTypeOfExpression typeOfExpression;
while (result != null) {
if ((primitiveEx = result as CodePrimitiveExpression) != null) {
Trace("Primitive. Value: {0}", (primitiveEx.Value == null ? "(null)" : primitiveEx.Value));
result = primitiveEx.Value;
break;
}
else if ((propertyReferenceEx = result as CodePropertyReferenceExpression) != null) {
result = DeserializePropertyReferenceExpression(manager, propertyReferenceEx, true);
break;
}
else if (result is CodeThisReferenceExpression) { //(is -> as doesn't help here, since the cast is different)
Trace("'this' reference");
RootContext rootExp = (RootContext)manager.Context[typeof(RootContext)];
if (rootExp != null) {
result = rootExp.Value;
}
else {
// Last ditch effort. Some things have to code gen against "this", such
// as event wireups. Those are always bounda against the root component.
IDesignerHost host = manager.GetService(typeof(IDesignerHost)) as IDesignerHost;
if (host != null) {
result = host.RootComponent;
}
}
if (result == null) {
TraceError("CodeThisReferenceExpression not handled because there is no root context or the root context did not contain an instance.");
Error(manager, SR.GetString(SR.SerializerNoRootExpression), SR.SerializerNoRootExpression);
}
break;
}
else if ((typeReferenceEx = result as CodeTypeReferenceExpression) != null) {
Trace("TypeReference : {0}", typeReferenceEx.Type.BaseType);
result = manager.GetType(GetTypeNameFromCodeTypeReference(manager, typeReferenceEx.Type));
break;
}
else if ((objectCreateEx = result as CodeObjectCreateExpression) != null) {
Trace("Object create");
result = null;
Type type = manager.GetType(GetTypeNameFromCodeTypeReference(manager, objectCreateEx.CreateType));
if (type != null) {
object[] parameters = new object[objectCreateEx.Parameters.Count];
bool paramsOk = true;
for (int i = 0; i < parameters.Length; i++) {
parameters[i] = DeserializeExpression(manager, null, objectCreateEx.Parameters[i]);
if (parameters[i] is CodeExpression) {
// Before we bail on this parameter, see if the type is a delegate.
// If we are creating a delegate we may be able to bind to the method
// after all.
if (typeof(Delegate).IsAssignableFrom(type) && parameters.Length == 1 && parameters[i] is CodeMethodReferenceExpression) {
CodeMethodReferenceExpression methodRef = (CodeMethodReferenceExpression)parameters[i];
// Only do this if our target is not the root context.
if (!(methodRef.TargetObject is CodeThisReferenceExpression)) {
object target = DeserializeExpression(manager, null, methodRef.TargetObject);
if (!(target is CodeExpression)) {
// Search for a matching method sig. Must be public since we don't own this
// object
MethodInfo delegateInvoke = type.GetMethod("Invoke");
if (delegateInvoke != null) {
ParameterInfo[] delegateParams = delegateInvoke.GetParameters();
Type[] paramTypes = new Type[delegateParams.Length];
for (int idx = 0; idx < paramTypes.Length; idx++) {
paramTypes[idx] = delegateParams[i].ParameterType;
}
MethodInfo mi = TypeDescriptor.GetReflectionType(target).GetMethod(methodRef.MethodName, paramTypes);
if (mi != null) {
result = Activator.CreateInstance(type, new object[] { target, mi.MethodHandle.GetFunctionPointer() });
}
}
}
}
}
// Technically, the paramters are not OK. Our special case above, if
// successful, would have produced a "result" object for us.
paramsOk = false;
break;
}
}
if (paramsOk) {
// Create an instance of the object. If the caller provided a name,
// then ask the manager to add this object to the container.
result = DeserializeInstance(manager, type, parameters, name, (name != null));
}
}
else {
TraceError("Type {0} could not be loaded", objectCreateEx.CreateType.BaseType);
Error(manager, SR.GetString(SR.SerializerTypeNotFound, objectCreateEx.CreateType.BaseType), SR.SerializerTypeNotFound);
}
break;
}
else if ((argumentReferenceEx = result as CodeArgumentReferenceExpression) != null) {
Trace("Named argument reference : {0}", argumentReferenceEx.ParameterName);
result = manager.GetInstance(argumentReferenceEx.ParameterName);
if (result == null) {
TraceError("Parameter {0} does not exist", argumentReferenceEx.ParameterName);
Error(manager, SR.GetString(SR.SerializerUndeclaredName, argumentReferenceEx.ParameterName), SR.SerializerUndeclaredName);
}
break;
}
else if ((fieldReferenceEx = result as CodeFieldReferenceExpression) != null) {
Trace("Field reference : {0}", fieldReferenceEx.FieldName);
object target = DeserializeExpression(manager, null, fieldReferenceEx.TargetObject);
if (target != null && !(target is CodeExpression)) {
// If the target is the root object, then this won't be found
// through reflection. Instead, ask the manager for the field
// by name.
//
RootContext rootExp = (RootContext)manager.Context[typeof(RootContext)];
if (rootExp != null && rootExp.Value == target) {
object namedObject = manager.GetInstance(fieldReferenceEx.FieldName);
if (namedObject != null) {
result = namedObject;
}
else {
TraceError("Field {0} could not be resolved", fieldReferenceEx.FieldName);
Error(manager, SR.GetString(SR.SerializerUndeclaredName, fieldReferenceEx.FieldName), SR.SerializerUndeclaredName);
}
}
else {
FieldInfo field;
object instance;
Type t = target as Type;
if (t != null) {
instance = null;
field = TypeDescriptor.GetReflectionType(t).GetField(fieldReferenceEx.FieldName, BindingFlags.GetField | BindingFlags.Static | BindingFlags.Public);
}
else {
instance = target;
field = TypeDescriptor.GetReflectionType(target).GetField(fieldReferenceEx.FieldName, BindingFlags.GetField | BindingFlags.Instance | BindingFlags.Public);
}
if (field != null) {
result = field.GetValue(instance);
}
else {
//lets try it as a property:
CodePropertyReferenceExpression propRef = new CodePropertyReferenceExpression();
propRef.TargetObject = fieldReferenceEx.TargetObject;
propRef.PropertyName = fieldReferenceEx.FieldName;
result = DeserializePropertyReferenceExpression(manager, propRef, false);
if (result == fieldReferenceEx) {
Error(manager, SR.GetString(SR.SerializerUndeclaredName, fieldReferenceEx.FieldName), SR.SerializerUndeclaredName);
}
}
}
}
else {
Error(manager, SR.GetString(SR.SerializerFieldTargetEvalFailed, fieldReferenceEx.FieldName), SR.SerializerFieldTargetEvalFailed);
}
TraceWarningIf(result == fieldReferenceEx, "Could not resolve field {0} to an object instance.", fieldReferenceEx.FieldName);
break;
}
else if ((methodInvokeEx = result as CodeMethodInvokeExpression) != null) {
Trace("Method invoke : {0}", methodInvokeEx.Method.MethodName);
object targetObject = DeserializeExpression(manager, null, methodInvokeEx.Method.TargetObject);
if (targetObject != null) {
object[] parameters = new object[methodInvokeEx.Parameters.Count];
bool paramsOk = true;
for (int i = 0; i < parameters.Length; i++) {
parameters[i] = DeserializeExpression(manager, null, methodInvokeEx.Parameters[i]);
if (parameters[i] is CodeExpression) {
paramsOk = false;
break;
}
}
if (paramsOk) {
IComponentChangeService compChange = (IComponentChangeService)manager.GetService(typeof(IComponentChangeService));
Type t = targetObject as Type;
if (t != null) {
result = TypeDescriptor.GetReflectionType(t).InvokeMember(methodInvokeEx.Method.MethodName, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, parameters, null, null, null);
}
else {
if (compChange != null) {
compChange.OnComponentChanging(targetObject, null);
}
try {
result = TypeDescriptor.GetReflectionType(targetObject).InvokeMember(methodInvokeEx.Method.MethodName, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance, null, targetObject, parameters, null, null, null);
}
catch (MissingMethodException) {
// We did not find the method directly. Let's see if we can find it
// as an private implemented interface name.
//
CodeCastExpression castExpr = methodInvokeEx.Method.TargetObject as CodeCastExpression;
if (castExpr != null) {
Type castType = manager.GetType(GetTypeNameFromCodeTypeReference(manager, castExpr.TargetType));
if (castType != null && castType.IsInterface) {
result = TypeDescriptor.GetReflectionType(castType).InvokeMember(methodInvokeEx.Method.MethodName, BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, targetObject, parameters, null, null, null);
}
else {
throw;
}
}
else {
throw;
}
}
if (compChange != null) {
compChange.OnComponentChanged(targetObject, null, null, null);
}
}
}
else if (parameters.Length == 1 && parameters[0] is CodeDelegateCreateExpression) {
string methodName = methodInvokeEx.Method.MethodName;
if (methodName.StartsWith("add_")) {
methodName = methodName.Substring(4);
DeserializeAttachEventStatement(manager, new CodeAttachEventStatement(methodInvokeEx.Method.TargetObject, methodName, (CodeExpression)parameters[0]));
result = null;
}
}
}
break;
}
else if ((variableReferenceEx = result as CodeVariableReferenceExpression) != null) {
Trace("Variable reference : {0}", variableReferenceEx.VariableName);
result = manager.GetInstance(variableReferenceEx.VariableName);
if (result == null) {
TraceError("Variable {0} does not exist", variableReferenceEx.VariableName);
Error(manager, SR.GetString(SR.SerializerUndeclaredName, variableReferenceEx.VariableName), SR.SerializerUndeclaredName);
}
break;
}
else if ((castEx = result as CodeCastExpression) != null) {
Trace("Cast : {0}", castEx.TargetType.BaseType);
result = DeserializeExpression(manager, name, castEx.Expression);
IConvertible ic = result as IConvertible;
if (ic != null) {
Type targetType = manager.GetType(GetTypeNameFromCodeTypeReference(manager, castEx.TargetType));
if (targetType != null) {
result = ic.ToType(targetType, null);
}
}
break;
}
else if (result is CodeBaseReferenceExpression) { //(is -> as doesn't help here, since the cast is different)
RootContext rootExp = (RootContext)manager.Context[typeof(RootContext)];
if (rootExp != null) {
result = rootExp.Value;
}
else {
result = null;
}
break;
}
else if ((arrayCreateEx = result as CodeArrayCreateExpression) != null) {
Trace("Array create : {0}", arrayCreateEx.CreateType.BaseType);
Type arrayType = manager.GetType(GetTypeNameFromCodeTypeReference(manager, arrayCreateEx.CreateType));
Array array = null;
if (arrayType != null) {
if (arrayCreateEx.Initializers.Count > 0) {
Trace("{0} initializers", arrayCreateEx.Initializers.Count);
// Passed an array of initializers. Use this
// to create the array. Note that we use an
// ArrayList here and add elements as we create them.
// It is possible that an element cannot be resolved.
// This is an error, but we do not want to tank the
// entire array. If we kicked out the entire statement,
// a missing control would cause all controls on a form
// to vanish.
ArrayList arrayList = new ArrayList(arrayCreateEx.Initializers.Count);
foreach (CodeExpression initializer in arrayCreateEx.Initializers) {
try {
object o = DeserializeExpression(manager, null, initializer);
if (!(o is CodeExpression)) {
if (!arrayType.IsInstanceOfType(o)) {
o = Convert.ChangeType(o, arrayType, CultureInfo.InvariantCulture);
}
arrayList.Add(o);
}
}
catch (Exception ex) {
manager.ReportError(ex);
}
}
array = Array.CreateInstance(arrayType, arrayList.Count);
arrayList.CopyTo(array, 0);
}
else if (arrayCreateEx.SizeExpression != null) {
object o = DeserializeExpression(manager, name, arrayCreateEx.SizeExpression);
Debug.Assert(o is IConvertible, "Array size expression could not be resolved to IConvertible: " + (o == null ? "(null)" : o.GetType().Name));
IConvertible ic = o as IConvertible;
if (ic != null) {
int size = ic.ToInt32(null);
Trace("Initialized with expression that simplified to {0}", size);
array = Array.CreateInstance(arrayType, size);
}
}
else {
Trace("Initialized with size {0}", arrayCreateEx.Size);
array = Array.CreateInstance(arrayType, arrayCreateEx.Size);
}
}
else {
TraceError("Type could not be resolved: {0}", arrayCreateEx.CreateType.BaseType);
Error(manager, SR.GetString(SR.SerializerTypeNotFound, arrayCreateEx.CreateType.BaseType), SR.SerializerTypeNotFound);
}
result = array;
if (result != null && name != null) {
manager.SetName(result, name);
}
break;
}
else if ((arrayIndexerEx = result as CodeArrayIndexerExpression) != null) {
Trace("Array indexer");
// For this, assume in any error we return a null. The only errors
// here should come from a mal-formed expression.
//
result = null;
Array array = DeserializeExpression(manager, name, arrayIndexerEx.TargetObject) as Array;
if (array != null) {
int[] indexes = new int[arrayIndexerEx.Indices.Count];
Trace("Dims: {0}", indexes.Length);
bool indexesOK = true;
// The indexes have to be of type int32. If they're not, then
// we cannot assign to this array.
//
for (int i = 0; i < indexes.Length; i++) {
IConvertible index = DeserializeExpression(manager, name, arrayIndexerEx.Indices[i]) as IConvertible;
if (index != null) {
indexes[i] = index.ToInt32(null);
Trace("[{0}] == {1}", i, indexes[i]);
}
else {
TraceWarning("Index {0} could not be converted to int. Type: {1}", i, (index == null ? "(null)" : index.GetType().Name));
indexesOK = false;
break;
}
}
if (indexesOK) {
result = array.GetValue(indexes);
}
}
break;
}
else if ((binaryOperatorEx = result as CodeBinaryOperatorExpression) != null) {
Trace("Binary operator : {0}", binaryOperatorEx.Operator);
object left = DeserializeExpression(manager, null, binaryOperatorEx.Left);
object right = DeserializeExpression(manager, null, binaryOperatorEx.Right);
// We assign the result to an arbitrary value here in case the operation could
// not be performed.
//
result = left;
IConvertible icLeft = left as IConvertible;
IConvertible icRight = right as IConvertible;
if (icLeft != null && icRight != null) {
result = ExecuteBinaryExpression(icLeft, icRight, binaryOperatorEx.Operator);
}
else {
TraceWarning("Could not simplify left and right binary operators to IConvertible.");
}
break;
}
else if ((delegateInvokeEx = result as CodeDelegateInvokeExpression) != null) {
Trace("Delegate invoke");
object targetObject = DeserializeExpression(manager, null, delegateInvokeEx.TargetObject);
Delegate del = targetObject as Delegate;
if (del != null) {
object[] parameters = new object[delegateInvokeEx.Parameters.Count];
bool paramsOk = true;
for (int i = 0; i < parameters.Length; i++) {
parameters[i] = DeserializeExpression(manager, null, delegateInvokeEx.Parameters[i]);
if (parameters[i] is CodeExpression) {
paramsOk = false;
break;
}
}
if (paramsOk) {
Trace("Invoking {0} with {1} parameters", targetObject.GetType().Name, parameters.Length);
del.DynamicInvoke(parameters);
}
}
break;
}
else if ((directionEx = result as CodeDirectionExpression) != null) {
Trace("Direction operator");
result = DeserializeExpression(manager, name, directionEx.Expression);
break;
}
else if ((indexerEx = result as CodeIndexerExpression) != null) {
Trace("Indexer");
// For this, assume in any error we return a null. The only errors
// here should come from a mal-formed expression.
//
result = null;
object targetObject = DeserializeExpression(manager, null, indexerEx.TargetObject);
if (targetObject != null) {
object[] indexes = new object[indexerEx.Indices.Count];
Trace("Indexes: {0}", indexes.Length);
bool indexesOK = true;
for (int i = 0; i < indexes.Length; i++) {
indexes[i] = DeserializeExpression(manager, null, indexerEx.Indices[i]);
if (indexes[i] is CodeExpression) {
TraceWarning("Index {0} could not be simplified to an object.", i);
indexesOK = false;
break;
}
}
if (indexesOK) {
result = TypeDescriptor.GetReflectionType(targetObject).InvokeMember("Item", BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance, null, targetObject, indexes, null, null, null);
}
}
break;
}
else if (result is CodeSnippetExpression) {
Trace("Snippet");
result = null;
break;
}
else if ((parameterDeclaration = result as CodeParameterDeclarationExpression) != null) {
Trace("Parameter declaration");
result = manager.GetType(GetTypeNameFromCodeTypeReference(manager, parameterDeclaration.Type));
break;
}
else if ((typeOfExpression = result as CodeTypeOfExpression) != null) {
Trace("Typeof({0})", typeOfExpression.Type.BaseType);
string type = GetTypeNameFromCodeTypeReference(manager, typeOfExpression.Type);
// add the array ranks so we get the right type of this thing.
//
for (int i = 0; i < typeOfExpression.Type.ArrayRank; i++) {
type += "[]";
}
result = manager.GetType(type);
if (result == null) {
TraceError("Type could not be resolved: {0}", type);
Error(manager, SR.GetString(SR.SerializerTypeNotFound, type), SR.SerializerTypeNotFound);
}
break;
}
else if (result is CodeEventReferenceExpression || result is CodeMethodReferenceExpression || result is CodeDelegateCreateExpression) {
// These are all the expressions we know about, but
// expect to return to the caller because we cannot
// simplify them.
//
break;
}
else {
// All expression evaluation happens above. This codepath
// indicates that we got some sort of junk in the evalualtor,
// or that someone assigned result to a value without
// breaking out of the loop.
//
Debug.Fail("Unrecognized expression type: " + result.GetType().Name);
break;
}
}
}
return result;
}
///
///
/// This method will inspect all of the properties on the given object fitting the filter, and check for that
/// property in a resource blob. This is useful for deserializing properties that cannot be represented
/// in code, such as design-time properties.
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")]
protected void DeserializePropertiesFromResources(IDesignerSerializationManager manager, object value, Attribute[] filter) {
using (TraceScope("ComponentCodeDomSerializerBase::DeserializePropertiesFromResources")) {
// It is much faster to dig through the resources first, and then map these resources
// to properties than it is to filter properties at each turn. Why? Because filtering
// properties requires a separate filter call for each object (because designers get a chance
// to filter, the cache is per-component), while resources are loaded once per
// document.
//
IDictionaryEnumerator de = ResourceCodeDomSerializer.Default.GetMetadataEnumerator(manager);
if (de == null) {
de = ResourceCodeDomSerializer.Default.GetEnumerator(manager, CultureInfo.InvariantCulture);
}
if (de != null) {
string ourObjectName;
RootContext root = manager.Context[typeof(RootContext)] as RootContext;
if (root != null && root.Value == value) {
ourObjectName = "$this";
}
else {
ourObjectName = manager.GetName(value);
}
PropertyDescriptorCollection ourProperties = TypeDescriptor.GetProperties(value);
while (de.MoveNext()) {
object current = de.Current;
string resourceName = de.Key as string;
Debug.Assert(resourceName != null, "non-string keys in dictionary entry");
int dotIndex = resourceName.IndexOf('.');
if (dotIndex == -1) {
continue;
}
string objectName = resourceName.Substring(0, dotIndex);
// Skip now if this isn't a value for our object.
//
if (!objectName.Equals(ourObjectName)) {
continue;
}
string propertyName = resourceName.Substring(dotIndex + 1);
// Now locate the property by this name.
//
PropertyDescriptor property = ourProperties[propertyName];
if (property == null) {
continue;
}
// This property must have matching attributes.
//
bool passFilter = true;
if (filter != null) {
AttributeCollection propAttributes = property.Attributes;
foreach (Attribute a in filter) {
if (!propAttributes.Contains(a)) {
passFilter = false;
break;
}
}
}
// If this property passes inspection, then set it.
//
if (passFilter) {
object resourceObject = de.Value;
Trace("Resource: {0}, value: {1}", resourceName, (resourceObject == null ? "(null)" : resourceObject));
try {
property.SetValue(value, resourceObject);
}
catch (Exception e) {
manager.ReportError(e);
}
}
}
}
}
}
///
///
/// This is a helper method that will deserialize a given statement. It deserializes
/// the statement by interpreting and executing the CodeDom statement.
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")]
protected void DeserializeStatement(IDesignerSerializationManager manager, CodeStatement statement) {
using (TraceScope("CodeDomSerializerBase::DeserializeStatement")) {
Trace("Statement : {0}", statement.GetType().Name);
// Push this statement onto the context stack. This allows any serializers handling an expression
// to know what it was connected to.
//
manager.Context.Push(statement);
try {
//Perf: is -> as changes, change ordering based on possibility of occurance
//Please excuse the bad formatting, but I think it is more readable this way than
//nested indenting.
CodeAssignStatement cas = statement as CodeAssignStatement;
if (cas != null) {
DeserializeAssignStatement(manager, cas);
}
else {
CodeVariableDeclarationStatement cvds = statement as CodeVariableDeclarationStatement;
if (cvds != null) {
DeserializeVariableDeclarationStatement(manager, cvds);
}
else if (statement is CodeCommentStatement) {
// do nothing for comments. This just supresses the debug warning
}
else {
CodeExpressionStatement ces = statement as CodeExpressionStatement;
if (ces != null) {
DeserializeExpression(manager, null, ces.Expression);
}
else {
CodeMethodReturnStatement cmrs = statement as CodeMethodReturnStatement;
if (cmrs != null) {
DeserializeExpression(manager, null, ces.Expression);
}
else {
CodeAttachEventStatement caes = statement as CodeAttachEventStatement;
if (caes != null) {
DeserializeAttachEventStatement(manager, caes);
}
else {
CodeRemoveEventStatement cres = statement as CodeRemoveEventStatement;
if (cres != null) {
DeserializeDetachEventStatement(manager, cres);
}
else {
CodeLabeledStatement cls = statement as CodeLabeledStatement;
if (cls != null) {
DeserializeStatement(manager, cls.Statement);
}
else {
TraceWarning("Unrecognized statement type: {0}", statement.GetType().Name);
}
}
}
}
}
}
} // yes, these paranthesis are needed
}
catch (CheckoutException) {
throw; // we want to propagate those all the way up
}
catch (Exception e) {
// Since we always go through reflection, don't
// show what our engine does, show what caused
// the problem.
//
if (e is TargetInvocationException) {
e = e.InnerException;
}
if (!(e is CodeDomSerializerException) && statement.LinePragma != null) {
e = new CodeDomSerializerException(e, statement.LinePragma);
}
manager.ReportError(e);
}
finally {
Debug.Assert(manager.Context.Current == statement, "Someone corrupted the context stack");
manager.Context.Pop();
}
}
}
private bool DeserializePropertyAssignStatement(IDesignerSerializationManager manager, CodeAssignStatement statement,
CodePropertyReferenceExpression propertyReferenceEx, bool reportError) {
Trace("LHS is property : {0}", propertyReferenceEx.PropertyName);
object lhs = DeserializeExpression(manager, null, propertyReferenceEx.TargetObject);
if (lhs != null && !(lhs is CodeExpression)) {
// Property assignments must go through our type descriptor system.
// However, we do not support parameterized properties. If there are
// any parameters on the property, we do not perform the assignment.
//
PropertyDescriptor p = TypeDescriptor.GetProperties(lhs, runTimeProperties)[propertyReferenceEx.PropertyName];
if (p != null) {
Trace("Processing RHS");
object rhs = DeserializeExpression(manager, null, statement.Right);
if (rhs is CodeExpression) {
TraceError("Unable to simplify statement to anything better than: {0}", rhs.GetType().Name);
return false;
}
IConvertible ic = rhs as IConvertible;
if (ic != null && p.PropertyType != rhs.GetType()) {
try {
rhs = ic.ToType(p.PropertyType, null);
}
catch {
// oh well...
}
}
//VSWhidbey#580599 We need to ensure that no virtual types leak into the runtime code
//So if we ever assign a property value to a Type -- we make sure that the Type is a
// real System.Type.
Type rhsType = rhs as Type;
if (rhsType != null && rhsType.UnderlyingSystemType != null)
{
rhs = rhsType.UnderlyingSystemType; //unwrap this "type" that came because it was not actually a real bcl type.
}
// Next: see if the RHS of this expression was a property reference too. If it was, then
// we will look for a MemberRelationshipService to record the relationship between these
// two properties, if supported.
// VSWhidbey 504238.
// We need to setup this MemberRelationship before we actually set the property value.
// If we do it the other way around the new property value will be pushed into the old
// relationship, which isn't a problem during normal serialization (since it not very
// likely the property has already been assigned to), but it does affect undo.
MemberRelationship oldRelation = MemberRelationship.Empty;
MemberRelationshipService relationships = null;
if (statement.Right is CodePropertyReferenceExpression) {
relationships = manager.GetService(typeof(MemberRelationshipService)) as MemberRelationshipService;
if (relationships != null) {
CodePropertyReferenceExpression rhsPropRef = (CodePropertyReferenceExpression)statement.Right;
object rhsPropTarget = DeserializeExpression(manager, null, rhsPropRef.TargetObject);
PropertyDescriptor rhsProp = TypeDescriptor.GetProperties(rhsPropTarget)[rhsPropRef.PropertyName];
if (rhsProp != null) {
MemberRelationship source = new MemberRelationship(lhs, p);
MemberRelationship target = new MemberRelationship(rhsPropTarget, rhsProp);
oldRelation = relationships[source];
if (relationships.SupportsRelationship(source, target)) {
relationships[source] = target;
}
}
}
}
else {
relationships = manager.GetService(typeof(MemberRelationshipService)) as MemberRelationshipService;
if (relationships != null) {
oldRelation = relationships[lhs, p];
relationships[lhs, p] = MemberRelationship.Empty;
}
}
try {
p.SetValue(lhs, rhs);
}
catch {
if (relationships != null) {
relationships[lhs, p] = oldRelation;
}
throw;
}
return true;
}
else {
if (reportError) {
TraceError("Object {0} does not have a property {1}", lhs.GetType().Name, propertyReferenceEx.PropertyName);
Error(manager, SR.GetString(SR.SerializerNoSuchProperty, lhs.GetType().FullName, propertyReferenceEx.PropertyName), SR.SerializerNoSuchProperty);
}
}
}
else {
TraceWarning("Could not find target object for property {0}", propertyReferenceEx.PropertyName);
}
return false;
}
///
///
/// Deserializes an assign statement by performing the assignment.
///
private void DeserializeAssignStatement(IDesignerSerializationManager manager, CodeAssignStatement statement) {
using (TraceScope("CodeDomSerializerBase::DeserializeAssignStatement")) {
// Since we're doing an assignment into something, we need to know
// what that something is. It can be a property, a variable, or
// a member. Anything else is invalid.
//
//Perf: is -> as changes, change ordering based on possibility of occurance
CodeExpression expression = statement.Left;
CodePropertyReferenceExpression propertyReferenceEx;
CodeFieldReferenceExpression fieldReferenceEx;
CodeVariableReferenceExpression variableReferenceEx;
CodeArrayIndexerExpression arrayIndexerEx;
Trace("Processing LHS");
if ((propertyReferenceEx = expression as CodePropertyReferenceExpression) != null) {
DeserializePropertyAssignStatement(manager, statement, propertyReferenceEx, true);
}
else if ((fieldReferenceEx = expression as CodeFieldReferenceExpression) != null) {
Trace("LHS is field : {0}", fieldReferenceEx.FieldName);
object lhs = DeserializeExpression(manager, fieldReferenceEx.FieldName, fieldReferenceEx.TargetObject);
if (lhs != null) {
RootContext root = (RootContext)manager.Context[typeof(RootContext)];
if (root != null && root.Value == lhs) {
Trace("Processing RHS");
object rhs = DeserializeExpression(manager, fieldReferenceEx.FieldName, statement.Right);
if (rhs is CodeExpression) {
TraceError("Unable to simplify statement to anything better than: {0}", rhs.GetType().Name);
return;
}
}
else {
FieldInfo f;
object instance;
Type type = lhs as Type;
if (type != null) {
instance = null;
f = TypeDescriptor.GetReflectionType(type).GetField(fieldReferenceEx.FieldName, BindingFlags.GetField | BindingFlags.Static | BindingFlags.Public);
}
else {
instance = lhs;
f = TypeDescriptor.GetReflectionType(lhs).GetField(fieldReferenceEx.FieldName, BindingFlags.GetField | BindingFlags.Instance | BindingFlags.Public);
}
if (f != null) {
Trace("Processing RHS");
object rhs = DeserializeExpression(manager, fieldReferenceEx.FieldName, statement.Right);
if (rhs is CodeExpression) {
TraceError("Unable to simplify statement to anything better than: {0}", rhs.GetType().Name);
return;
}
IConvertible ic = rhs as IConvertible;
if (ic != null && f.FieldType != rhs.GetType()) {
try {
rhs = ic.ToType(f.FieldType, null);
}
catch {
// oh well...
}
}
f.SetValue(instance, rhs);
}
else {
//lets try it as a property:
CodePropertyReferenceExpression propRef = new CodePropertyReferenceExpression();
propRef.TargetObject = fieldReferenceEx.TargetObject;
propRef.PropertyName = fieldReferenceEx.FieldName;
if (!DeserializePropertyAssignStatement(manager, statement, propRef, false)) {
TraceError("Object {0} does not have a field {1}", lhs.GetType().Name, fieldReferenceEx.FieldName);
Error(manager, SR.GetString(SR.SerializerNoSuchField, lhs.GetType().FullName, fieldReferenceEx.FieldName), SR.SerializerNoSuchField);
}
}
}
}
else {
TraceWarning("Could not find target object for field {0}", fieldReferenceEx.FieldName);
}
}
else if ((variableReferenceEx = expression as CodeVariableReferenceExpression) != null) {
// This is the easiest. Just relate the RHS object to the name of the variable.
//
Trace("Processing RHS");
object rhs = DeserializeExpression(manager, variableReferenceEx.VariableName, statement.Right);
if (rhs is CodeExpression) {
TraceError("Unable to simplify statement to anything better than: {0}", rhs.GetType().Name);
return;
}
manager.SetName(rhs, variableReferenceEx.VariableName);
}
else if ((arrayIndexerEx = expression as CodeArrayIndexerExpression) != null) {
int[] indexes = new int[arrayIndexerEx.Indices.Count];
Trace("LHS is Array Indexer with dims {0}", indexes.Length);
object array = DeserializeExpression(manager, null, arrayIndexerEx.TargetObject);
bool indexesOK = true;
// The indexes have to be of type int32. If they're not, then
// we cannot assign to this array.
//
for (int i = 0; i < indexes.Length; i++) {
object index = DeserializeExpression(manager, null, arrayIndexerEx.Indices[i]);
IConvertible ic = index as IConvertible;
if (ic != null) {
indexes[i] = ic.ToInt32(null);
Trace("[{0}] == {1}", i, indexes[i]);
}
else {
TraceWarning("Index {0} could not be converted to int. Type: {1}", i, (index == null ? "(null)" : index.GetType().Name));
indexesOK = false;
break;
}
}
Array arr = array as Array;
if (arr != null && indexesOK) {
Trace("Processing RHS");
object rhs = DeserializeExpression(manager, null, statement.Right);
if (rhs is CodeExpression) {
TraceError("Unable to simplify statement to anything better than: {0}", rhs.GetType().Name);
return;
}
arr.SetValue(rhs, indexes);
}
else {
TraceErrorIf(!(array is Array), "Array resovled to something other than an array: {0}", (array == null ? "(null)" : array.GetType().Name));
TraceErrorIf(!indexesOK, "Indexes to array could not be converted to int32.");
}
}
}
}
///
///
/// Deserializes the event attachment by setting the event value throught IEventBindingService.
///
private void DeserializeAttachEventStatement(IDesignerSerializationManager manager, CodeAttachEventStatement statement) {
using (TraceScope("CodeDomSerializerBase::DeserializeAttachEventStatement")) {
string handlerMethodName = null;
object eventAttachObject = null;
// Get the target information
//
object targetObject = DeserializeExpression(manager, null, statement.Event.TargetObject);
string eventName = statement.Event.EventName;
Debug.Assert(targetObject != null, "Failed to get target object for event attach");
Debug.Assert(eventName != null, "Failed to get eventName for event attach");
if (eventName == null || targetObject == null) {
return;
}
CodeObjectCreateExpression objCreate = statement.Listener as CodeObjectCreateExpression;
if (objCreate != null) {
// now walk into the CodeObjectCreateExpression and get the parameters so we can
// get the name of the method, e.g. button1_Click
//
if (objCreate.Parameters.Count == 1) {
// if this is a delegate create (new EventHandler(this.button1_Click)), then
// the first parameter should be a method ref.
//
CodeMethodReferenceExpression methodRef = objCreate.Parameters[0] as CodeMethodReferenceExpression;
if (methodRef != null) {
handlerMethodName = methodRef.MethodName;
eventAttachObject = DeserializeExpression(manager, null, methodRef.TargetObject);
}
}
else {
Debug.Fail("Encountered delegate object create with more or less than 1 parameter?");
}
}
else {
object eventListener = DeserializeExpression(manager, null, statement.Listener);
CodeDelegateCreateExpression delegateCreate = eventListener as CodeDelegateCreateExpression;
if (delegateCreate != null) {
eventAttachObject = DeserializeExpression(manager, null, delegateCreate.TargetObject);
handlerMethodName = delegateCreate.MethodName;
}
}
RootContext rootExp = (RootContext)manager.Context[typeof(RootContext)];
bool isRoot = rootExp == null || (rootExp != null && rootExp.Value == eventAttachObject);
if (handlerMethodName == null) {
TraceError("Unable to retrieve handler method and object for delegate create.");
}
else {
// We only support binding methods to the root object.
//
TraceWarningIf(!isRoot, "Event is bound to an object other than the root. We do not support this.");
if (isRoot) {
// Now deserialize the LHS of the event attach to discover the guy whose
// event we are attaching.
//
TraceErrorIf(targetObject is CodeExpression, "Unable to simplify event attach LHS to an object reference.");
if (!(targetObject is CodeExpression)) {
EventDescriptor evt = TypeDescriptor.GetEvents(targetObject)[eventName];
if (evt != null) {
IEventBindingService evtSvc = (IEventBindingService)manager.GetService(typeof(IEventBindingService));
if (evtSvc != null) {
PropertyDescriptor prop = evtSvc.GetEventProperty(evt);
prop.SetValue(targetObject, handlerMethodName);
Trace("Attached event {0}.{1} to {2}", targetObject.GetType().Name, eventName, handlerMethodName);
}
}
else {
TraceError("Object {0} does not have a event {1}", targetObject.GetType().Name, eventName);
Error(manager, SR.GetString(SR.SerializerNoSuchEvent, targetObject.GetType().FullName, eventName), SR.SerializerNoSuchEvent);
}
}
}
}
}
}
///
///
/// Deserializes the event detachment by setting the event value throught IEventBindingService.
///
private void DeserializeDetachEventStatement(IDesignerSerializationManager manager, CodeRemoveEventStatement statement) {
using (TraceScope("CodeDomSerializerBase::DeserializeDetachEventStatement")) {
object eventListener = DeserializeExpression(manager, null, statement.Listener);
TraceErrorIf(!(eventListener is CodeDelegateCreateExpression), "Unable to simplify event attach RHS to a delegate create.");
CodeDelegateCreateExpression delegateCreate = eventListener as CodeDelegateCreateExpression;
if (delegateCreate != null) {
// We only support binding methods to the root object.
//
object eventAttachObject = DeserializeExpression(manager, null, delegateCreate.TargetObject);
RootContext rootExp = (RootContext)manager.Context[typeof(RootContext)];
bool isRoot = rootExp == null || (rootExp != null && rootExp.Value == eventAttachObject);
TraceWarningIf(!isRoot, "Event is bound to an object other than the root. We do not support this.");
if (isRoot) {
// Now deserialize the LHS of the event attach to discover the guy whose
// event we are attaching.
//
object targetObject = DeserializeExpression(manager, null, statement.Event.TargetObject);
TraceErrorIf(targetObject is CodeExpression, "Unable to simplify event attach LHS to an object reference.");
if (!(targetObject is CodeExpression)) {
EventDescriptor evt = TypeDescriptor.GetEvents(targetObject)[statement.Event.EventName];
if (evt != null) {
IEventBindingService evtSvc = (IEventBindingService)manager.GetService(typeof(IEventBindingService));
if (evtSvc != null) {
PropertyDescriptor prop = evtSvc.GetEventProperty(evt);
prop.SetValue(targetObject, null);
}
}
else {
TraceError("Object {0} does not have a event {1}", targetObject.GetType().Name, statement.Event.EventName);
Error(manager, SR.GetString(SR.SerializerNoSuchEvent, targetObject.GetType().FullName, statement.Event.EventName), SR.SerializerNoSuchEvent);
}
}
}
}
}
}
///
///
/// Deserializes a variable declaration by deserializing the target object of the variable and providing a name.
///
private void DeserializeVariableDeclarationStatement(IDesignerSerializationManager manager, CodeVariableDeclarationStatement statement) {
using (TraceScope("CodeDomSerializerBase::DeserializeVariableDeclarationStatement")) {
if (statement.InitExpression != null) {
Trace("Processing init expression");
DeserializeExpression(manager, statement.Name, statement.InitExpression);
}
}
}
///
///
/// This creates a new exception object with the given string. It attempts to discover the
/// current statement, and if it can find one, will create a CodeDomSerializerException that
/// contains the correct file / line number information. After creating the exception, it
/// throws it.
///
internal void Error(IDesignerSerializationManager manager, string exceptionText, string helpLink) {
if (manager == null) throw new ArgumentNullException("manager");
if (exceptionText == null) throw new ArgumentNullException("exceptionText");
CodeStatement statement = (CodeStatement)manager.Context[typeof(CodeStatement)];
CodeLinePragma linePragma = null;
if (statement != null) {
linePragma = statement.LinePragma;
}
Exception exception = new CodeDomSerializerException(exceptionText, linePragma);
exception.HelpLink = helpLink;
throw exception;
}
///
///
/// Executes the given binary expression. If at any stage of the game the expression execution fails,
/// this just returns the default value for the datatype required by the operator. Boolean == false,
/// for example.
///
private object ExecuteBinaryExpression(IConvertible left, IConvertible right, CodeBinaryOperatorType op) {
// "Binary" operator type is actually a combination of several types of operators: boolean, binary
// and math. Group them into categories here.
//
CodeBinaryOperatorType[] booleanOperators = new CodeBinaryOperatorType[] {
CodeBinaryOperatorType.IdentityInequality,
CodeBinaryOperatorType.IdentityEquality,
CodeBinaryOperatorType.ValueEquality,
CodeBinaryOperatorType.BooleanOr,
CodeBinaryOperatorType.BooleanAnd,
CodeBinaryOperatorType.LessThan,
CodeBinaryOperatorType.LessThanOrEqual,
CodeBinaryOperatorType.GreaterThan,
CodeBinaryOperatorType.GreaterThanOrEqual
};
CodeBinaryOperatorType[] mathOperators = new CodeBinaryOperatorType[] {
CodeBinaryOperatorType.Add,
CodeBinaryOperatorType.Subtract,
CodeBinaryOperatorType.Multiply,
CodeBinaryOperatorType.Divide,
CodeBinaryOperatorType.Modulus
};
CodeBinaryOperatorType[] binaryOperators = new CodeBinaryOperatorType[] {
CodeBinaryOperatorType.BitwiseOr,
CodeBinaryOperatorType.BitwiseAnd
};
// Figure out what kind of expression we have.
//
for (int i = 0; i < binaryOperators.Length; i++) {
if (op == binaryOperators[i]) {
return ExecuteBinaryOperator(left, right, op);
}
}
for (int i = 0; i < mathOperators.Length; i++) {
if (op == mathOperators[i]) {
return ExecuteMathOperator(left, right, op);
}
}
for (int i = 0; i < booleanOperators.Length; i++) {
if (op == booleanOperators[i]) {
return ExecuteBooleanOperator(left, right, op);
}
}
Debug.Fail("Unsupported binary operator type: " + op.ToString());
return left;
}
///
///
/// Executes the given binary operator. If at any stage of the game the expression execution fails,
/// this just returns the left hand side.
/// for example.
///
private object ExecuteBinaryOperator(IConvertible left, IConvertible right, CodeBinaryOperatorType op) {
TypeCode leftType = left.GetTypeCode();
TypeCode rightType = right.GetTypeCode();
// The compatible types are listed in order from lowest bitness to highest. We must
// operate on the highest bitness to keep fidelity.
//
TypeCode[] compatibleTypes = new TypeCode[] {
TypeCode.Byte,
TypeCode.Char,
TypeCode.Int16,
TypeCode.UInt16,
TypeCode.Int32,
TypeCode.UInt32,
TypeCode.Int64,
TypeCode.UInt64};
int leftTypeIndex = -1;
int rightTypeIndex = -1;
for (int i = 0; i < compatibleTypes.Length; i++) {
if (leftType == compatibleTypes[i]) {
leftTypeIndex = i;
}
if (rightType == compatibleTypes[i]) {
rightTypeIndex = i;
}
if (leftTypeIndex != -1 && rightTypeIndex != -1) {
break;
}
}
if (leftTypeIndex == -1 || rightTypeIndex == -1) {
Debug.Fail("Could not convert left or right side to binary-compatible value.");
return left;
}
int maxIndex = Math.Max(leftTypeIndex, rightTypeIndex);
object result = left;
switch (compatibleTypes[maxIndex]) {
case TypeCode.Byte: {
byte leftValue = left.ToByte(null);
byte rightValue = right.ToByte(null);
if (op == CodeBinaryOperatorType.BitwiseOr) {
result = leftValue | rightValue;
}
else {
result = leftValue & rightValue;
}
break;
}
case TypeCode.Char: {
char leftValue = left.ToChar(null);
char rightValue = right.ToChar(null);
if (op == CodeBinaryOperatorType.BitwiseOr) {
result = leftValue | rightValue;
}
else {
result = leftValue & rightValue;
}
break;
}
case TypeCode.Int16: {
short leftValue = left.ToInt16(null);
short rightValue = right.ToInt16(null);
if (op == CodeBinaryOperatorType.BitwiseOr) {
result = (short)((ushort)leftValue | (ushort)rightValue);
}
else {
result = leftValue & rightValue;
}
break;
}
case TypeCode.UInt16: {
ushort leftValue = left.ToUInt16(null);
ushort rightValue = right.ToUInt16(null);
if (op == CodeBinaryOperatorType.BitwiseOr) {
result = leftValue | rightValue;
}
else {
result = leftValue & rightValue;
}
break;
}
case TypeCode.Int32: {
int leftValue = left.ToInt32(null);
int rightValue = right.ToInt32(null);
if (op == CodeBinaryOperatorType.BitwiseOr) {
result = leftValue | rightValue;
}
else {
result = leftValue & rightValue;
}
break;
}
case TypeCode.UInt32: {
uint leftValue = left.ToUInt32(null);
uint rightValue = right.ToUInt32(null);
if (op == CodeBinaryOperatorType.BitwiseOr) {
result = leftValue | rightValue;
}
else {
result = leftValue & rightValue;
}
break;
}
case TypeCode.Int64: {
long leftValue = left.ToInt64(null);
long rightValue = right.ToInt64(null);
if (op == CodeBinaryOperatorType.BitwiseOr) {
result = leftValue | rightValue;
}
else {
result = leftValue & rightValue;
}
break;
}
case TypeCode.UInt64: {
ulong leftValue = left.ToUInt64(null);
ulong rightValue = right.ToUInt64(null);
if (op == CodeBinaryOperatorType.BitwiseOr) {
result = leftValue | rightValue;
}
else {
result = leftValue & rightValue;
}
break;
}
}
if (result != left && left is Enum) {
// For enums, try to convert back to the original type
//
result = Enum.ToObject(left.GetType(), result);
}
return result;
}
///
///
/// Executes the given boolean operator. If at any stage of the game the expression execution fails,
/// this just returns false.
/// for example.
///
private object ExecuteBooleanOperator(IConvertible left, IConvertible right, CodeBinaryOperatorType op) {
bool result = false;
switch (op) {
case CodeBinaryOperatorType.IdentityInequality:
result = (left != right);
break;
case CodeBinaryOperatorType.IdentityEquality:
result = (left == right);
break;
case CodeBinaryOperatorType.ValueEquality:
result = left.Equals(right);
break;
case CodeBinaryOperatorType.BooleanOr:
result = (left.ToBoolean(null) || right.ToBoolean(null));
break;
case CodeBinaryOperatorType.BooleanAnd:
result = (left.ToBoolean(null) && right.ToBoolean(null));
break;
case CodeBinaryOperatorType.LessThan:
// Not doing these at design time.
break;
case CodeBinaryOperatorType.LessThanOrEqual:
// Not doing these at design time.
break;
case CodeBinaryOperatorType.GreaterThan:
// Not doing these at design time.
break;
case CodeBinaryOperatorType.GreaterThanOrEqual:
// Not doing these at design time.
break;
default:
Debug.Fail("Should never get here!");
break;
}
return result;
}
///
///
/// Executes the given math operator. If at any stage of the game the expression execution fails,
/// this just returns the left hand side.
/// for example.
///
private object ExecuteMathOperator(IConvertible left, IConvertible right, CodeBinaryOperatorType op) {
switch (op) {
case CodeBinaryOperatorType.Add:
string leftString = left as string;
string rightString = right as string;
if (leftString == null && left is Char) {
leftString = left.ToString();
}
if (rightString == null && right is Char) {
rightString = right.ToString();
}
if (leftString != null && rightString != null) {
return leftString + rightString;
}
else {
Debug.Fail("Addition operator not supported for this type");
return left;
}
default:
Debug.Fail("Math operators are not supported");
return left;
}
}
///
///
/// This method returns an expression representing the given object. It may return null, indicating that
/// no expression has been set that describes the object. Expressions are aquired in one of three ways:
///
/// 1. The expression could be the result of a prior SetExpression call.
/// 2. The expression could have been found in the RootContext.
/// 3. The expression could be derived through IReferenceService.
/// 4. The current expression on the context stack has a PresetValue == value.
///
/// To derive expressions through IReferenceService, GetExpression asks the reference service if there
/// is a name for the given object. If the expression service returns a valid name, it checks to see if
/// there is a '.' in the name. This indicates that the expression service found this object as the return
/// value of a read only property on another object. If there is a '.', GetExpression will split the reference
/// into sub-parts. The leftmost part is a name that will be evalulated via manager.GetInstance. For each
/// subsequent part, a property reference expression will be built. The final expression will then be returned.
///
/// If the object did not have an expression set, or the object was not found in the reference service, null will
/// be returned from GetExpression, indicating there is no existing expression for the object.
///
protected CodeExpression GetExpression(IDesignerSerializationManager manager, object value) {
CodeExpression expression = null;
if (manager == null) {
throw new ArgumentNullException("manager");
}
if (value == null) {
throw new ArgumentNullException("value");
}
Trace("GetExpression called for object {0}", value.ToString());
// Is the expression part of a prior SetExpression call?
ExpressionTable table = manager.Context[typeof(ExpressionTable)] as ExpressionTable;
if (table != null) {
expression = table.GetExpression(value);
TraceIf(expression != null, "Resolved through expression table : {0}", expression);
}
// Check to see if this object represents the root context.
if (expression == null) {
RootContext rootEx = manager.Context[typeof(RootContext)] as RootContext;
if (rootEx != null && object.ReferenceEquals(rootEx.Value, value)) {
expression = rootEx.Expression;
TraceIf(expression != null, "Resolved through root expression context : {0}", expression);
}
}
// Now check IReferenceService.
if (expression == null) {
// perf: first try to retrieve objectName from DesignerSerializationManager
// only then involve reference service if needed
// this is done to avoid unnecessary ensuring\creating references
string objectName = manager.GetName(value);
if (objectName == null || objectName.IndexOf('.') != -1)
{
IReferenceService refSvc = manager.GetService(typeof(IReferenceService)) as IReferenceService;
if (refSvc != null)
{
objectName = refSvc.GetName(value);
if (objectName != null && objectName.IndexOf('.') != -1)
{
Trace("Resolving through IReferenceService : {0}", objectName);
// This object name is built from sub objects. Assemble the graph of sub objects.
string[] nameParts = objectName.Split('.');
Debug.Assert(nameParts.Length > 0, "How can we fail to split when IndexOf succeeded?");
object baseInstance = manager.GetInstance(nameParts[0]);
TraceWarningIf(baseInstance == null, "Manager can't return an instance for object {0}", nameParts[0]);
if (baseInstance != null)
{
CodeExpression baseExpression = SerializeToExpression(manager, baseInstance);
TraceWarningIf(baseExpression == null, "Unable to serialize object {0} to an expression.", baseInstance);
if (baseExpression != null)
{
for (int idx = 1; idx < nameParts.Length; idx++)
{
baseExpression = new CodePropertyReferenceExpression(baseExpression, nameParts[idx]);
}
expression = baseExpression;
}
}
}
}
}
}
// Finally, the expression context.
if (expression == null) {
ExpressionContext cxt = manager.Context[typeof(ExpressionContext)] as ExpressionContext;
if (cxt != null && object.ReferenceEquals(cxt.PresetValue, value)) {
expression = cxt.Expression;
}
}
if (expression != null) {
// set up cache dependencies
// we check to see if there is anything on the stack
// if there is we make the parent entry a dependency of the current entry
ComponentCache.Entry parentEntry = (ComponentCache.Entry)manager.Context[typeof(ComponentCache.Entry)];
ComponentCache cache = (ComponentCache)manager.Context[typeof(ComponentCache)];
if (parentEntry != null && parentEntry.Component != value /* don't make ourselves dependent with ourselves */ && cache != null) {
ComponentCache.Entry entry = null;
entry = cache.GetEntryAll(value);
if (entry != null && parentEntry.Component != null) {
entry.AddDependency(parentEntry.Component);
}
}
}
return expression;
}
// undone : we need this for backwards compat with the serializaiton code in M.VS.dll. Rip this when we rip that code.
private PropertyDescriptorCollection GetFilteredProperties(IDesignerSerializationManager manager, object value, Attribute[] filter) {
IComponent comp = value as IComponent;
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(value, filter);
if (comp != null) {
if (((IDictionary)props).IsReadOnly) {
PropertyDescriptor[] propArray = new PropertyDescriptor[props.Count];
props.CopyTo(propArray, 0);
props = new PropertyDescriptorCollection(propArray);
}
PropertyDescriptor filterProp = manager.Properties["FilteredProperties"];
if (filterProp != null) {
ITypeDescriptorFilterService filterSvc = filterProp.GetValue(manager) as ITypeDescriptorFilterService;
if (filterSvc != null) {
filterSvc.FilterProperties(comp, props);
}
}
}
return props;
}
private CodeExpression GetLegacyExpression(IDesignerSerializationManager manager, object value) {
LegacyExpressionTable table = manager.Context[typeof(LegacyExpressionTable)] as LegacyExpressionTable;
CodeExpression expression = null;
if (table != null) {
object exp = table[value];
if (exp == value) {
// Sentinel. Compute an actual legacy expression to store.
string name = manager.GetName(value);
bool referenceName = false;
if (name == null) {
IReferenceService referenceService = (IReferenceService)manager.GetService(typeof(IReferenceService));
if (referenceService != null) {
name = referenceService.GetName(value);
referenceName = name != null;
}
}
if (name != null) {
Trace("Object is reference ({0}) Creating reference expression", name);
// Check to see if this is a reference to the root component. If it is, then use "this".
//
RootContext root = (RootContext)manager.Context[typeof(RootContext)];
if (root != null) {
if (root.Value == value) {
expression = root.Expression;
}
else if (referenceName && name.IndexOf('.') != -1) {
// if it's a reference name with a dot, we've actually got a property here...
//
int dotIndex = name.IndexOf('.');
expression = new CodePropertyReferenceExpression(new CodeFieldReferenceExpression(root.Expression, name.Substring(0, dotIndex)), name.Substring(dotIndex + 1));
}
else {
expression = new CodeFieldReferenceExpression(root.Expression, name);
}
}
else {
// A variable reference
if (referenceName && name.IndexOf('.') != -1) {
// if it's a reference name with a dot, we've actually got a property here...
//
int dotIndex = name.IndexOf('.');
expression = new CodePropertyReferenceExpression(new CodeVariableReferenceExpression(name.Substring(0, dotIndex)), name.Substring(dotIndex + 1));
}
else {
expression = new CodeVariableReferenceExpression(name);
}
}
}
table[value] = expression;
}
else {
expression = exp as CodeExpression;
}
}
return expression;
}
///
///
/// Returns the serializer for the given value. This is cognizant that instance
/// attributes may be different from type attributes and will use a custom serializer
/// on the instance if it is present. If not, it will delegate to the serialization
/// manager.
///
protected CodeDomSerializer GetSerializer(IDesignerSerializationManager manager, object value) {
if (value != null) {
AttributeCollection valueAttributes = TypeDescriptor.GetAttributes(value);
AttributeCollection typeAttributes = TypeDescriptor.GetAttributes(value.GetType());
if (valueAttributes.Count != typeAttributes.Count) {
// Ok, someone has stuffed custom attributes on this instance. Since
// the serialization manager only takes types, we've got to see if
// one of these custom attributes is a designer serializer attribute.
string valueSerializerTypeName = null;
Type desiredSerializerType = typeof(CodeDomSerializer);
foreach (Attribute a in valueAttributes) {
DesignerSerializerAttribute da = a as DesignerSerializerAttribute;
if (da != null) {
Type realSerializerType = manager.GetType(da.SerializerBaseTypeName);
if (realSerializerType == desiredSerializerType) {
valueSerializerTypeName = da.SerializerTypeName;
break;
}
}
}
// If we got a value serializer, we've got to do the same thing
// here for the type serializer. We only care if the two
// are different
if (valueSerializerTypeName != null) {
foreach (Attribute a in typeAttributes) {
DesignerSerializerAttribute da = a as DesignerSerializerAttribute;
if (da != null) {
Type realSerializerType = manager.GetType(da.SerializerBaseTypeName);
if (realSerializerType == desiredSerializerType) {
// Ok, we found a serializer. If it matches the
// one we found for the value, then we can still
// use the default implementation.
if (valueSerializerTypeName.Equals(da.SerializerTypeName)) {
valueSerializerTypeName = null;
}
break;
}
}
}
}
// Finally, if we got a value serializer, we need to create it and use it.
if (valueSerializerTypeName != null) {
Type serializerType = manager.GetType(valueSerializerTypeName);
if (serializerType != null && desiredSerializerType.IsAssignableFrom(serializerType)) {
return (CodeDomSerializer)Activator.CreateInstance(serializerType);
}
}
}
}
// for serializing null, we pass null to the serialization manager
// otherwise, external IDesignerSerializationProviders wouldn't be given a chance to
// serialize null their own special way.
Type t = null;
if (value != null) {
t = value.GetType();
}
return (CodeDomSerializer)manager.GetSerializer(t, typeof(CodeDomSerializer));
}
///
///
/// Returns the serializer for the given value. This is cognizant that instance
/// attributes may be different from type attributes and will use a custom serializer
/// on the instance if it is present. If not, it will delegate to the serialization
/// manager.
///
protected CodeDomSerializer GetSerializer(IDesignerSerializationManager manager, Type valueType) {
return manager.GetSerializer(valueType, typeof(CodeDomSerializer)) as CodeDomSerializer;
}
[SuppressMessage("Microsoft.Performance", "CA1801:AvoidUnusedParameters")]
protected bool IsSerialized(IDesignerSerializationManager manager, object value) {
return IsSerialized(manager, value, false);
}
///
///
/// This method returns true if the given value has been serialized before. For an object to
/// be considered serialized either it or another serializer must have called SetExpression, creating
/// a relationship between that object and a referring expression.
///
[SuppressMessage("Microsoft.Performance", "CA1801:AvoidUnusedParameters")]
protected bool IsSerialized(IDesignerSerializationManager manager, object value, bool honorPreset) {
bool hasExpression = false;
if (manager == null) {
throw new ArgumentNullException("manager");
}
if (value == null) {
throw new ArgumentNullException("value");
}
// Is the expression part of a prior SetExpression call?
ExpressionTable table = manager.Context[typeof(ExpressionTable)] as ExpressionTable;
if (table != null && table.GetExpression(value) != null && (!honorPreset || !table.ContainsPresetExpression(value))) {
hasExpression = true;
}
Trace("IsSerialized called for object {0} : {1}", value, hasExpression);
return hasExpression;
}
///
///
/// This method can be used to serialize an expression that represents the creation of the given object.
/// It is aware of instance descriptors and will return true for isComplete if the entire configuration for the
/// instance could be achieved.
///
protected CodeExpression SerializeCreationExpression(IDesignerSerializationManager manager, object value, out bool isComplete) {
isComplete = false;
if (manager == null) {
throw new ArgumentNullException("manager");
}
if (value == null) {
throw new ArgumentNullException("value");
}
TypeConverter converter = TypeDescriptor.GetConverter(value);
// See if there is an ExpressionContext with a preset value we're interested in. If so,
// that will dictate our creation expression.
ExpressionContext cxt = manager.Context[typeof(ExpressionContext)] as ExpressionContext;
if (cxt != null && object.ReferenceEquals(cxt.PresetValue, value)) {
CodeExpression expression = cxt.Expression;
//Okay, we found a preset creation expression. We just need to find if it isComplete.
if (converter.CanConvertTo(typeof(InstanceDescriptor))) {
InstanceDescriptor descriptor = converter.ConvertTo(value, typeof(InstanceDescriptor)) as InstanceDescriptor;
if (descriptor != null && descriptor.MemberInfo != null) {
isComplete = descriptor.IsComplete;
}
}
return expression;
}
// See if there is an instance descriptor for this type.
if (converter.CanConvertTo(typeof(InstanceDescriptor))) {
InstanceDescriptor descriptor = converter.ConvertTo(value, typeof(InstanceDescriptor)) as InstanceDescriptor;
if (descriptor != null && descriptor.MemberInfo != null) {
isComplete = descriptor.IsComplete;
return SerializeInstanceDescriptor(manager, value, descriptor);
}
}
// see if this thing is serialiable
if (TypeDescriptor.GetReflectionType(value).IsSerializable && !(value is IComponent && ((IComponent)value).Site != null)) {
CodeExpression expression = SerializeToResourceExpression(manager, value);
TraceIf(expression != null, "Serialized value as a resource.");
if (expression != null) {
isComplete = true;
return expression;
}
}
// No instance descriptor. See if we can get to a public constructor that takes no arguments
Type type = TypeDescriptor.GetReflectionType(value);
ConstructorInfo ctor = type.GetConstructor(new Type[0]);
if (ctor != null) {
isComplete = false;
return new CodeObjectCreateExpression(TypeDescriptor.GetClassName(value), new CodeExpression[0]);
}
// Nothing worked.
return null;
}
///
///
/// This method returns a unique name for the given object. It first calls GetName from the serialization
/// manager, and if this does not return a name if fabricates a name for the object. To fabricate a name
/// it uses the INameCreationService to create valid names. If the service is not available instead the
/// method will fabricate a name based on the short type name combined with an index number to make
/// it unique. The resulting name is associated with the serialization manager by calling SetName before
/// the new name is returned.
///
protected string GetUniqueName(IDesignerSerializationManager manager, object value) {
if (manager == null) {
throw new ArgumentNullException("manager");
}
if (value == null) {
throw new ArgumentNullException("value");
}
string name = manager.GetName(value);
if (name == null) {
string baseName;
Type targetType = TypeDescriptor.GetReflectionType(value);
INameCreationService ns = manager.GetService(typeof(INameCreationService)) as INameCreationService;
TraceWarningIf(ns == null, "Need to generate a unique name but we have no name creation service.");
if (ns != null) {
baseName = ns.CreateName(null, targetType);
}
else {
baseName = targetType.Name.ToLower(CultureInfo.InvariantCulture);
}
int suffixIndex = 1;
ComponentCache cache = manager.Context[typeof(ComponentCache)] as ComponentCache;
// Declare this name to the serializer. If there is already a name defined,
// keep trying.
//
while (true) {
name = string.Format(CultureInfo.CurrentCulture, "{0}{1}", baseName, suffixIndex);
if (manager.GetInstance(name) == null && (cache == null || !cache.ContainsLocalName(name))) {
manager.SetName(value, name);
ComponentCache.Entry entry = manager.Context[typeof(ComponentCache.Entry)] as ComponentCache.Entry;
if (entry != null) {
entry.AddLocalName(name);
}
break;
}
suffixIndex++;
}
}
return name;
}
///
///
/// This serializes a single event for the given object.
///
protected void SerializeEvent(IDesignerSerializationManager manager, CodeStatementCollection statements, object value, EventDescriptor descriptor) {
if (manager == null) throw new ArgumentNullException("manager");
if (statements == null) throw new ArgumentNullException("statements");
if (value == null) throw new ArgumentNullException("value");
if (descriptor == null) throw new ArgumentNullException("descriptor");
using (TraceScope("CodeDomSerializerBase::SerializeEvent")) {
Trace("Name: {0}", descriptor.Name);
// Now look for a MemberCodeDomSerializer for the property. If we can't find one, then we can't serialize
// the property
manager.Context.Push(statements);
manager.Context.Push(descriptor);
try {
MemberCodeDomSerializer memberSerializer = (MemberCodeDomSerializer)manager.GetSerializer(descriptor.GetType(), typeof(MemberCodeDomSerializer));
TraceErrorIf(memberSerializer == null, "Event {0} cannot be serialized because it has no serializer.", descriptor.Name);
if (memberSerializer != null && memberSerializer.ShouldSerialize(manager, value, descriptor)) {
memberSerializer.Serialize(manager, value, descriptor, statements);
}
}
finally {
Debug.Assert(manager.Context.Current == descriptor, "Context stack corrupted.");
manager.Context.Pop();
manager.Context.Pop();
}
}
}
///
///
/// This serializes all events for the given object.
///
protected void SerializeEvents(IDesignerSerializationManager manager, CodeStatementCollection statements, object value, params Attribute[] filter) {
Trace("CodeDomSerializerBase::SerializeEvents");
// Now walk the events.
//
EventDescriptorCollection events = TypeDescriptor.GetEvents(value, filter).Sort();
foreach (EventDescriptor evt in events) {
SerializeEvent(manager, statements, value, evt);
}
}
///
///
/// Serializes the given instance descriptor into a code model expression.
///
private CodeExpression SerializeInstanceDescriptor(IDesignerSerializationManager manager, object value, InstanceDescriptor descriptor) {
CodeExpression expression = null;
using (TraceScope("CodeDomSerializerBase::SerializeInstanceDescriptor")) {
Trace("Member : {0}, args : {1}", descriptor.MemberInfo.Name, descriptor.Arguments.Count);
// Serialize all of the arguments.
//
CodeExpression[] arguments = new CodeExpression[descriptor.Arguments.Count];
object[] argumentValues = new object[arguments.Length];
ParameterInfo[] parameters = null;
if (arguments.Length > 0) {
descriptor.Arguments.CopyTo(argumentValues, 0);
MethodBase mi = descriptor.MemberInfo as MethodBase;
if (mi != null) {
parameters = mi.GetParameters();
}
}
bool paramsOk = true;
for (int i = 0; i < arguments.Length; i++) {
Debug.Assert(argumentValues != null && parameters != null, "These should have been allocated when the argument array was created.");
object arg = argumentValues[i];
CodeExpression exp = null;
ExpressionContext newCxt = null;
ExpressionContext cxt = manager.Context[typeof(ExpressionContext)] as ExpressionContext;
// If there is an ExpressionContext on the stack, we need to fix up its type to be
// the parameter type, so the argument objects get serialized correctly.
if (cxt != null) {
newCxt = new ExpressionContext(cxt.Expression, parameters[i].ParameterType, cxt.Owner);
manager.Context.Push(newCxt);
}
try {
exp = SerializeToExpression(manager, arg);
}
finally {
if (newCxt != null) {
Debug.Assert(manager.Context.Current == newCxt, "Context stack corrupted.");
manager.Context.Pop();
}
}
if (exp != null) {
// Assign over. See if we need a cast first.
if (arg != null && !parameters[i].ParameterType.IsAssignableFrom(arg.GetType())) {
exp = new CodeCastExpression(parameters[i].ParameterType, exp);
}
arguments[i] = exp;
}
else {
TraceWarning("Parameter {0} in instance descriptor call {1} could not be serialized.", i, descriptor.GetType().Name);
paramsOk = false;
break;
}
}
if (paramsOk) {
Type expressionType = descriptor.MemberInfo.DeclaringType;
CodeTypeReference typeRef = new CodeTypeReference(expressionType);
if (descriptor.MemberInfo is ConstructorInfo) {
expression = new CodeObjectCreateExpression(typeRef, arguments);
}
else if (descriptor.MemberInfo is MethodInfo) {
CodeTypeReferenceExpression typeRefExp = new CodeTypeReferenceExpression(typeRef);
CodeMethodReferenceExpression methodRef = new CodeMethodReferenceExpression(typeRefExp, descriptor.MemberInfo.Name);
expression = new CodeMethodInvokeExpression(methodRef, arguments);
expressionType = ((MethodInfo)descriptor.MemberInfo).ReturnType;
}
else if (descriptor.MemberInfo is PropertyInfo) {
CodeTypeReferenceExpression typeRefExp = new CodeTypeReferenceExpression(typeRef);
CodePropertyReferenceExpression propertyRef = new CodePropertyReferenceExpression(typeRefExp, descriptor.MemberInfo.Name);
Debug.Assert(arguments.Length == 0, "Property serialization does not support arguments");
expression = propertyRef;
expressionType = ((PropertyInfo)descriptor.MemberInfo).PropertyType;
}
else if (descriptor.MemberInfo is FieldInfo) {
Debug.Assert(arguments.Length == 0, "Field serialization does not support arguments");
CodeTypeReferenceExpression typeRefExp = new CodeTypeReferenceExpression(typeRef);
expression = new CodeFieldReferenceExpression(typeRefExp, descriptor.MemberInfo.Name);
expressionType = ((FieldInfo)descriptor.MemberInfo).FieldType;
}
else {
Debug.Fail("Unrecognized reflection type in instance descriptor: " + descriptor.MemberInfo.GetType().Name);
}
// Finally, check to see if our value is assignable from the expression type. If not,
// then supply a cast. The value may be an internal or protected type; if it is,
// then walk up its hierarchy until we find one that is public.
//
Type targetType = value.GetType();
while (!targetType.IsPublic) {
targetType = targetType.BaseType;
}
if (!targetType.IsAssignableFrom(expressionType)) {
Trace("Supplying cast from {0} to {1}.", expressionType.Name, targetType.Name);
expression = new CodeCastExpression(targetType, expression);
}
}
}
return expression;
}
///
///
/// This serializes all properties for the given object, using the provided filter.
///
protected void SerializeProperties(IDesignerSerializationManager manager, CodeStatementCollection statements, object value, Attribute[] filter) {
using (TraceScope("CodeDomSerializerBase::SerializeProperties")) {
// Now walk the properties.
//
PropertyDescriptorCollection properties = GetFilteredProperties(manager, value, filter).Sort();
InheritanceAttribute inheritance = (InheritanceAttribute)TypeDescriptor.GetAttributes(value)[typeof(InheritanceAttribute)];
if (inheritance == null) {
inheritance = InheritanceAttribute.NotInherited;
}
manager.Context.Push(inheritance);
try {
foreach (PropertyDescriptor property in properties) {
if (!property.Attributes.Contains(DesignerSerializationVisibilityAttribute.Hidden)) {
SerializeProperty(manager, statements, value, property);
}
}
}
finally {
Debug.Assert(manager.Context.Current == inheritance, "Sombody messed up our context stack.");
manager.Context.Pop();
}
}
}
///
///
/// This method will inspect all of the properties on the given object fitting the filter, and check for that
/// property in a resource blob. This is useful for deserializing properties that cannot be represented
/// in code, such as design-time properties.
///
protected void SerializePropertiesToResources(IDesignerSerializationManager manager, CodeStatementCollection statements, object value, Attribute[] filter) {
using (TraceScope("ComponentCodeDomSerializerBase::SerializePropertiesToResources")) {
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(value, filter);
manager.Context.Push(statements);
try {
CodeExpression target = SerializeToExpression(manager, value);
if (target != null) {
CodePropertyReferenceExpression propertyRef = new CodePropertyReferenceExpression(target, string.Empty);
foreach (PropertyDescriptor property in props) {
TraceWarningIf(property.Attributes.Contains(DesignerSerializationVisibilityAttribute.Content), "PersistContents property " + property.Name + " cannot be serialized to resources.");
ExpressionContext tree = new ExpressionContext(propertyRef, property.PropertyType, value);
manager.Context.Push(tree);
try {
if (property.Attributes.Contains(DesignerSerializationVisibilityAttribute.Visible)) {
propertyRef.PropertyName = property.Name;
Trace("Property : {0}", property.Name);
string name;
if (target is CodeThisReferenceExpression) {
name = "$this";
}
else {
name = manager.GetName(value);
}
name = string.Format(CultureInfo.CurrentCulture, "{0}.{1}", name, property.Name);
ResourceCodeDomSerializer.Default.SerializeMetadata(manager, name, property.GetValue(value), property.ShouldSerializeValue(value));
}
}
finally {
Debug.Assert(manager.Context.Current == tree, "Context stack corrupted.");
manager.Context.Pop();
}
}
}
}
finally {
Debug.Assert(manager.Context.Current == statements, "Context stack corrupted.");
manager.Context.Pop();
}
}
}
///
///
/// This serializes the given proeprty for the given object.
///
protected void SerializeProperty(IDesignerSerializationManager manager, CodeStatementCollection statements, object value, PropertyDescriptor propertyToSerialize) {
if (manager == null) throw new ArgumentNullException("manager");
if (value == null) throw new ArgumentNullException("value");
if (propertyToSerialize == null) throw new ArgumentNullException("propertyToSerialize");
if (statements == null) throw new ArgumentNullException("statements");
Trace("CodeDomSerializerBase::SerializeProperty {0}", propertyToSerialize.Name);
// Now look for a MemberCodeDomSerializer for the property. If we can't find one, then we can't serialize
// the property
manager.Context.Push(statements);
manager.Context.Push(propertyToSerialize);
try {
MemberCodeDomSerializer memberSerializer = (MemberCodeDomSerializer)manager.GetSerializer(propertyToSerialize.GetType(), typeof(MemberCodeDomSerializer));
TraceErrorIf(memberSerializer == null, "Property {0} cannot be serialized because it has no serializer.", propertyToSerialize.Name);
if (memberSerializer != null && memberSerializer.ShouldSerialize(manager, value, propertyToSerialize)) {
memberSerializer.Serialize(manager, value, propertyToSerialize, statements);
}
}
finally {
Debug.Assert(manager.Context.Current == propertyToSerialize, "Context stack corrupted.");
manager.Context.Pop();
manager.Context.Pop();
}
}
///
///
/// Writes the given resource value under the given name. The resource is written to the
/// current CultureInfo the user is using to design with.
///
protected void SerializeResource(IDesignerSerializationManager manager, string resourceName, object value) {
ResourceCodeDomSerializer.Default.WriteResource(manager, resourceName, value);
}
///
///
/// Writes the given resource value under the given name. The resource is written to the
/// invariant culture.
///
protected void SerializeResourceInvariant(IDesignerSerializationManager manager, string resourceName, object value) {
ResourceCodeDomSerializer.Default.WriteResourceInvariant(manager, resourceName, value);
}
///
///
/// This is a helper method that serializes a value to an expression. It will return a CodeExpression if the
/// value can be serialized, or null if it can't. SerializeToExpression uses the following rules for serializing types:
/// 1. It first calls GetExpression to see if an expression has already been created for the object. If so, it
/// returns the existing expression.
/// 2. It then locates the object's serializer, and asks it to serialize.
/// 3. If the return value of the object's serializer is a CodeExpression, the expression is returned.
/// 4. It finally makes one last call to GetExpression to see if the serializer added an expression.
/// 5. Finally, it returns null.
///
/// If no expression could be created and no suitable serializer could be found, an error will be
/// reported through the serialization manager. No error will be reported if a serializer was found
/// but it failed to produce an expression. It is assumed that the serializer either already reported
/// the error, or does not wish to serialize the object.
///
protected CodeExpression SerializeToExpression(IDesignerSerializationManager manager, object value) {
CodeExpression expression = null;
using (TraceScope("SerializeToExpression")) {
// We do several things here:
//
// First, we check to see if there is already an expression for this object by calling
// IsSerialized / GetExpression.
//
// Failing that we check GetLegacyExpression to see if we are working with an old serializer.
//
// Failing that, we invoke the object's serializer. If that serializer returned a CodeExpression,
// we will use it.
//
// If the serializer did not return a code expression, we call GetExpression one last time to
// see if the serializer added an expression. If it did, we use it. Otherwise we return
// null.
//
// If the serializer was invoked and it created one or more statements those statements will
// be added to a statement collection. Additionally, if there is a statement context that contains
// a statement table for this object we will push that statement table onto the context stack in
// case someone else needs statements.
if (value != null) {
if (IsSerialized(manager, value)) {
expression = GetExpression(manager, value);
TraceIf(expression != null, "Existing expression found : {0}", expression);
}
else {
expression = GetLegacyExpression(manager, value);
if (expression != null) {
TraceWarning("Using legacy expression guard to prevent recursion. Serializer for {0} should be rewritten to handle GetExpression / SetExpression.", value);
SetExpression(manager, value, expression);
}
}
}
if (expression == null) {
CodeDomSerializer serializer = GetSerializer(manager, value);
if (serializer != null) {
Trace("Invoking serializer {0}", serializer.GetType().Name);
CodeStatementCollection saveStatements = null;
if (value != null) {
// The Whidbey model for serializing a complex object is to call
// SetExpression with the object's reference expression and then
// call on the various Serialize Property / Event methods. This is
// incompatible with legacy code, and if not handled legacy code may
// serialize incorrectly or even stack fault. To handle this, we keep
// a private "Legacy Expression Table". This is a table that we fill in
// here. We don't fill in the actual legacy expression here. Rather,
// we fill it with a marker value and obtain the legacy expression
// above in GetLegacyExpression. If we hit this case, we then save
// the expression in GetExpression so that future calls to IsSerialized
// will succeed.
SetLegacyExpression(manager, value);
StatementContext statementCxt = manager.Context[typeof(StatementContext)] as StatementContext;
if (statementCxt != null) {
saveStatements = statementCxt.StatementCollection[value];
}
if (saveStatements != null) {
manager.Context.Push(saveStatements);
}
}
object result = null;
try {
result = serializer.Serialize(manager, value);
}
finally {
if (saveStatements != null) {
Debug.Assert(manager.Context.Current == saveStatements, "Context stack corrupted.");
manager.Context.Pop();
}
}
expression = result as CodeExpression;
if (expression == null && value != null) {
expression = GetExpression(manager, value);
}
// If the result is a statement or a group of statements, we need to
// see if there is a code statement collection on the stack we can push the
// statements into.
CodeStatementCollection statements = result as CodeStatementCollection;
if (statements == null) {
CodeStatement statement = result as CodeStatement;
if (statement != null) {
statements = new CodeStatementCollection();
statements.Add(statement);
}
}
if (statements != null) {
Trace("Serialization produced additional statements");
// See if we have a place for these statements to be stored. If not, then
// check the context.
if (saveStatements == null) {
saveStatements = manager.Context[typeof(CodeStatementCollection)] as CodeStatementCollection;
}
if (saveStatements != null) {
Trace("Saving in context stack statement collection");
Debug.Assert(saveStatements != statements, "The serializer returned the same collection that exists on the context stack.");
saveStatements.AddRange(statements);
}
else {
// If we got here we will be losing data because we have no avenue to save these statements. Inform the user.
string valueName = "(null)";
if (value != null) {
valueName = manager.GetName(value);
if (valueName == null) {
valueName = value.GetType().Name;
}
}
TraceError("Serialization produced a set of statements but there is no statement collection on the stack to receive them.");
manager.ReportError(SR.GetString(SR.SerializerLostStatements, valueName));
}
}
}
else {
TraceError("No serializer for data type: {0}", (value == null ? "(null)" : value.GetType().Name));
manager.ReportError(SR.GetString(SR.SerializerNoSerializerForComponent, value.GetType().FullName));
}
}
}
return expression;
}
///
///
/// Serializes the given object to a resource and returns a code expression that represents the resource.
/// This will return null if the value cannot be serialized. If ensureInvariant is true, this will ensure that
/// new values make their way into the invariant culture. Normally, this is desirable. Otherwise a resource
/// GetValue call could fail if reading from a culture that doesn't have a value. You should only pass
/// false to ensureInvariant when you intend to read resources differently than directly asking for a value.
/// The default value of insureInvariant is true.
///
protected CodeExpression SerializeToResourceExpression(IDesignerSerializationManager manager, object value) {
return SerializeToResourceExpression(manager, value, true);
}
///
///
/// Serializes the given object to a resource and returns a code expression that represents the resource.
/// This will return null if the value cannot be serialized. If ensureInvariant is true, this will ensure that
/// new values make their way into the invariant culture. Normally, this is desirable. Otherwise a resource
/// GetValue call could fail if reading from a culture that doesn't have a value. You should only pass
/// false to ensureInvariant when you intend to read resources differently than directly asking for a value.
/// The default value of insureInvariant is true.
///
protected CodeExpression SerializeToResourceExpression(IDesignerSerializationManager manager, object value, bool ensureInvariant) {
CodeExpression result = null;
if (value == null || value.GetType().IsSerializable) {
CodeStatementCollection saveStatements = null;
if (value != null) {
StatementContext statementCxt = manager.Context[typeof(StatementContext)] as StatementContext;
if (statementCxt != null) {
saveStatements = statementCxt.StatementCollection[value];
}
if (saveStatements != null) {
manager.Context.Push(saveStatements);
}
}
try {
result = ResourceCodeDomSerializer.Default.Serialize(manager, value, false, ensureInvariant) as CodeExpression;
}
finally {
if (saveStatements != null) {
Debug.Assert(manager.Context.Current == saveStatements, "Context stack corrupted.");
manager.Context.Pop();
}
}
}
return result;
}
[SuppressMessage("Microsoft.Performance", "CA1801:AvoidUnusedParameters")]
protected void SetExpression(IDesignerSerializationManager manager, object value, CodeExpression expression) {
SetExpression(manager, value, expression, false);
}
///
///
/// This is a helper method that associates a CodeExpression with an object. Objects that have been associated
/// with expressions in this way are accessible through the GetExpression method. SetExpression stores its
/// expression table as an appended object on the context stack so it is accessible by any serializer's
/// GetExpression method.
///
[SuppressMessage("Microsoft.Performance", "CA1801:AvoidUnusedParameters")]
protected void SetExpression(IDesignerSerializationManager manager, object value, CodeExpression expression, bool isPreset) {
if (manager == null) {
throw new ArgumentNullException("manager");
}
if (value == null) {
throw new ArgumentNullException("value");
}
if (expression == null) {
throw new ArgumentNullException("expression");
}
ExpressionTable table = (ExpressionTable)manager.Context[typeof(ExpressionTable)];
if (table == null) {
table = new ExpressionTable();
manager.Context.Append(table);
}
Trace("Set expression {0} for object {1}", expression, value);
// in debug builds, save off who performed this set expression. It's
// very valuable to know.
#if DEBUG
if (traceSerialization.TraceVerbose) {
expression.UserData["StackTrace"] = Environment.StackTrace;
}
else {
// Default to off as snapping the stack takes too much time in DEBUG to leave on permanently.
expression.UserData["StackTrace"] = "To enable - turn on DesignerSerialization TraceSwitch";
}
CodeExpression existingExpression = table.GetExpression(value);
if (existingExpression != null && !isPreset) {
Debug.Fail("There shouldn't be an expression already associated with this object : " + manager.GetName(value));
string stack = existingExpression.UserData["StackTrace"] as string;
if (stack == null) {
stack = "unknown";
}
TraceWarning("Duplicate expression on context stack for value {0}. Original expression callstack: {1}", value, stack);
}
#endif
table.SetExpression(value, expression, isPreset);
}
///
/// This method configures "value" to support a legacy expression, enabling legacy serialization and
/// preventing recursion.
///
private void SetLegacyExpression(IDesignerSerializationManager manager, object value) {
if (value is IComponent) {
LegacyExpressionTable table = (LegacyExpressionTable)manager.Context[typeof(LegacyExpressionTable)];
if (table == null) {
table = new LegacyExpressionTable();
manager.Context.Append(table);
}
table[value] = value;
}
}
///
/// Tracing functions for debugging.
///
[Conditional("DEBUG")]
internal static void Trace(string message, params object[] values) {
if (traceSerialization.TraceVerbose) {
int indent = 0;
int oldIndent = Debug.IndentLevel;
if (traceScope != null) indent = traceScope.Count;
try {
Debug.IndentLevel = indent;
Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, message, values));
}
finally {
Debug.IndentLevel = oldIndent;
}
}
}
///
/// Tracing functions for debugging.
///
[Conditional("DEBUG")]
internal static void Trace(CodeTypeDeclaration typeDecl) {
if (traceSerialization.TraceInfo) {
Debug.WriteLine("---------------------------- Generated Code ----------------------------");
System.IO.StringWriter sw = new System.IO.StringWriter(CultureInfo.InvariantCulture);
new Microsoft.CSharp.CSharpCodeProvider().GenerateCodeFromType(typeDecl, sw, new CodeGeneratorOptions());
Debug.WriteLine(sw.ToString());
}
}
///
/// Tracing functions for debugging.
///
[Conditional("DEBUG")]
internal static void TraceError(string message, params object[] values) {
if (traceSerialization.TraceError) {
string scope = string.Empty;
if (traceScope != null) {
foreach (string scopeName in traceScope) {
if (scope.Length > 0) {
scope = "/" + scope;
}
scope = scopeName + scope;
}
}
Debug.WriteLine("***************************************************");
Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "*** ERROR :{0}", string.Format(CultureInfo.CurrentCulture, message, values)));
Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "*** SCOPE :{0}", scope));
Debug.WriteLine("***************************************************");
}
}
///
/// Tracing functions for debugging.
///
[Conditional("DEBUG")]
internal static void TraceErrorIf(bool condition, string message, params object[] values) {
if (condition) TraceError(message, values);
}
///
/// Tracing functions for debugging.
///
[Conditional("DEBUG")]
internal static void TraceIf(bool condition, string message, params object[] values) {
if (condition) Trace(message, values);
}
///
/// Tracing functions for debugging.
///
internal static IDisposable TraceScope(string name) {
#if DEBUG
if (traceScope == null) {
traceScope = new Stack();
}
Trace(name);
traceScope.Push(name);
#endif
return new TracingScope();
}
///
/// Tracing functions for debugging.
///
[Conditional("DEBUG")]
internal static void TraceWarning(string message, params object[] values) {
if (traceSerialization.TraceWarning) {
string scope = string.Empty;
if (traceScope != null) {
foreach (string scopeName in traceScope) {
if (scope.Length > 0) {
scope = "/" + scope;
}
scope = scopeName + scope;
}
}
Debug.WriteLine("***************************************************");
Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "*** WARNING :{0}", string.Format(CultureInfo.CurrentCulture, message, values)));
Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "*** SCOPE :{0}", scope));
Debug.WriteLine("***************************************************");
}
}
///
/// Tracing functions for debugging.
///
[Conditional("DEBUG")]
internal static void TraceWarningIf(bool condition, string message, params object[] values) {
if (condition) TraceWarning(message, values);
}
private class LegacyExpressionTable : Hashtable {
}
private struct TracingScope : IDisposable {
public void Dispose() {
if (traceScope != null) traceScope.Pop();
}
}
///
/// Utility method that adds the given statement to our _statementTable dictionary under the
/// given name.
///
private static void AddStatement(IDictionary table, string name, CodeStatement statement) {
OrderedCodeStatementCollection statements;
if (table.Contains(name)) {
statements = (OrderedCodeStatementCollection)table[name];
}
else {
// push in an order key so we know what position this item was in the list of declarations.
// this allows us to preserve ZOrder.
//
statements = new OrderedCodeStatementCollection();
statements.Order = table.Count;
statements.Name = name;
table[name] = statements;
}
statements.Add(statement);
}
internal static Type GetType(ITypeResolutionService trs, string name, Dictionary names) {
Type type = null;
if (names != null && names.ContainsKey(name)) {
string typeName = names[name];
if (trs != null && !string.IsNullOrEmpty(typeName)) {
type = trs.GetType(typeName, false);
}
}
return type;
}
internal static void FillStatementTable(IDesignerSerializationManager manager, IDictionary table, CodeStatementCollection statements) {
FillStatementTable(manager, table, null, statements, null);
}
///
/// For those statements who
/// have a LHS that points to a name in our nametable, we add the statement to a Statement
/// Collection within the table dictionary. This allows us to very quickly
/// put to gether what statements are associated with what names.
/// The return value of this method is a list of statements that have no
/// LHS. The CodeDomComponentSerializationService needs this to
/// ensure it deserializes all the required statements
///
internal static void FillStatementTable(IDesignerSerializationManager manager, IDictionary table, Dictionary names, CodeStatementCollection statements, string className) {
using (TraceScope("CodeDomSerializerBase::FillStatementTable")) {
// Statements we look for.
CodeAssignStatement assign;
CodeAttachEventStatement attachEvent;
CodeRemoveEventStatement removeEvent;
CodeExpressionStatement expressionStmt = null;
CodeVariableDeclarationStatement variableDecl;
ITypeResolutionService trs = manager.GetService(typeof(ITypeResolutionService)) as ITypeResolutionService;
// Look in the method body to try to find statements with a LHS that
// points to a name in our nametable.
foreach (CodeStatement statement in statements) {
CodeExpression expression = null;
if ((assign = statement as CodeAssignStatement) != null) {
Trace("Processing CodeAssignStatement");
expression = assign.Left;
}
else if ((attachEvent = statement as CodeAttachEventStatement) != null) {
Trace("Processing CodeAttachEventStatement");
expression = attachEvent.Event;
}
else if ((removeEvent = statement as CodeRemoveEventStatement) != null) {
Trace("Processing CodeRemoveEventStatement");
expression = removeEvent.Event;
}
else if ((expressionStmt = statement as CodeExpressionStatement) != null) {
Trace("Processing CodeExpressionStatement");
expression = expressionStmt.Expression;
}
else if ((variableDecl = statement as CodeVariableDeclarationStatement) != null) {
Trace("Processing CodeVariableDeclarationStatement");
AddStatement(table, variableDecl.Name, variableDecl);
if (names != null && variableDecl.Type != null && !string.IsNullOrEmpty(variableDecl.Type.BaseType)) {
names[variableDecl.Name] = GetTypeNameFromCodeTypeReference(manager, variableDecl.Type);
}
expression = null;
}
// Expressions we look for.
CodeCastExpression castEx;
CodeDelegateCreateExpression delegateCreateEx;
CodeDelegateInvokeExpression delegateInvokeEx;
CodeDirectionExpression directionEx;
CodeEventReferenceExpression eventReferenceEx;
CodeMethodInvokeExpression methodInvokeEx;
CodeMethodReferenceExpression methodReferenceEx;
CodeArrayIndexerExpression arrayIndexerEx;
CodeFieldReferenceExpression fieldReferenceEx;
CodePropertyReferenceExpression propertyReferenceEx;
CodeVariableReferenceExpression variableReferenceEx;
if (expression != null) {
// Simplify the expression as much as we can, looking for our target
// object in the process. If we find an expression that refers to our target
// object, we're done and can move on to the next statement.
while (true) {
if ((castEx = expression as CodeCastExpression) != null) {
Trace("Simplifying CodeCastExpression");
expression = castEx.Expression;
}
else if ((delegateCreateEx = expression as CodeDelegateCreateExpression) != null) {
Trace("Simplifying CodeDelegateCreateExpression");
expression = delegateCreateEx.TargetObject;
}
else if ((delegateInvokeEx = expression as CodeDelegateInvokeExpression) != null) {
Trace("Simplifying CodeDelegateInvokeExpression");
expression = delegateInvokeEx.TargetObject;
}
else if ((directionEx = expression as CodeDirectionExpression) != null) {
Trace("Simplifying CodeDirectionExpression");
expression = directionEx.Expression;
}
else if ((eventReferenceEx = expression as CodeEventReferenceExpression) != null) {
Trace("Simplifying CodeEventReferenceExpression");
expression = eventReferenceEx.TargetObject;
}
else if ((methodInvokeEx = expression as CodeMethodInvokeExpression) != null) {
Trace("Simplifying CodeMethodInvokeExpression");
expression = methodInvokeEx.Method;
}
else if ((methodReferenceEx = expression as CodeMethodReferenceExpression) != null) {
Trace("Simplifying CodeMethodReferenceExpression");
expression = methodReferenceEx.TargetObject;
}
else if ((arrayIndexerEx = expression as CodeArrayIndexerExpression) != null) {
Trace("Simplifying CodeArrayIndexerExpression");
expression = arrayIndexerEx.TargetObject;
}
else if ((fieldReferenceEx = expression as CodeFieldReferenceExpression) != null) {
// For fields we need to check to see if the field name is equal to the target object.
// If it is, then we have the expression we want. We can add the statement here
// and then break out of our loop.
//
// Note: We cannot validate that this is a name in our nametable. The nametable
// only contains names we have discovered through code parsing and will not include
// data from any inherited objects. We accept the field now, and then fail later
// if we try to resolve it to an object and we can't find it.
//
bool addedStatement = false;
if (fieldReferenceEx.TargetObject is CodeThisReferenceExpression) {
Type type = GetType(trs, fieldReferenceEx.FieldName, names);
if (type != null) {
CodeDomSerializer serializer = manager.GetSerializer(type, typeof(CodeDomSerializer)) as CodeDomSerializer;
if (serializer != null) {
string componentName = serializer.GetTargetComponentName(statement, expression, type);
if (!string.IsNullOrEmpty(componentName)) {
AddStatement(table, componentName, statement);
addedStatement = true;
}
}
}
if (!addedStatement) {
// we still want to do this in case of the "Note" above.
AddStatement(table, fieldReferenceEx.FieldName, statement);
}
break;
}
else {
Trace("Simplifying CodeFieldReferenceExpression");
expression = fieldReferenceEx.TargetObject;
}
}
else if ((propertyReferenceEx = expression as CodePropertyReferenceExpression) != null) {
// For properties we need to check to see if the property name is equal to the target object.
// If it is, then we have the expression we want. We can add the statement here
// and then break out of our loop.
//
if (propertyReferenceEx.TargetObject is CodeThisReferenceExpression && (names == null || names.ContainsKey(propertyReferenceEx.PropertyName))) {
AddStatement(table, propertyReferenceEx.PropertyName, statement);
break;
}
else {
Trace("Simplifying CodePropertyReferenceExpression");
expression = propertyReferenceEx.TargetObject;
}
}
else if ((variableReferenceEx = expression as CodeVariableReferenceExpression) != null) {
// For variables we need to check to see if the variable name is equal to the target object.
// If it is, then we have the expression we want. We can add the statement here
// and then break out of our loop.
//
bool statementAdded = false;
if (names != null) {
Type type = GetType(trs, variableReferenceEx.VariableName, names);
if (type != null) {
CodeDomSerializer serializer = manager.GetSerializer(type, typeof(CodeDomSerializer)) as CodeDomSerializer;
if (serializer != null) {
string componentName = serializer.GetTargetComponentName(statement, expression, type);
if (!string.IsNullOrEmpty(componentName)) {
AddStatement(table, componentName, statement);
statementAdded = true;
}
}
}
}
else {
AddStatement(table, variableReferenceEx.VariableName, statement);
statementAdded = true;
}
if (!statementAdded) {
TraceError("Variable {0} used before it was declared.", variableReferenceEx.VariableName);
manager.ReportError(new CodeDomSerializerException(SR.GetString(SR.SerializerUndeclaredName, variableReferenceEx.VariableName), manager));
}
break;
}
else if (expression is CodeThisReferenceExpression || expression is CodeBaseReferenceExpression) {
// We cannot go any further than "this". So, we break out
// of the loop. We file this statement under the root object.
//
Debug.Assert(className != null, "FillStatementTable expected a valid className but received null");
if (className != null) {
AddStatement(table, className, statement);
}
break;
}
else {
// We cannot simplify this expression any further, so we stop looping.
//
break;
}
}
}
}
}
}
internal class OrderedCodeStatementCollection : CodeStatementCollection {
public int Order;
public string Name;
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SqlHelper.cs
- Baml2006ReaderFrame.cs
- RegexWorker.cs
- ScriptResourceHandler.cs
- GenericTypeParameterBuilder.cs
- SuppressIldasmAttribute.cs
- SchemaTableColumn.cs
- ProvidersHelper.cs
- PersonalizableAttribute.cs
- FixedFindEngine.cs
- ReliableDuplexSessionChannel.cs
- SafeViewOfFileHandle.cs
- PartBasedPackageProperties.cs
- SchemaType.cs
- IPCCacheManager.cs
- counter.cs
- JumpTask.cs
- XmlSchemaRedefine.cs
- OnOperation.cs
- DetailsViewPagerRow.cs
- METAHEADER.cs
- DrawListViewColumnHeaderEventArgs.cs
- HashCodeCombiner.cs
- UserControlCodeDomTreeGenerator.cs
- ParallelEnumerable.cs
- ComboBoxRenderer.cs
- GlobalProxySelection.cs
- OleDbDataReader.cs
- FormCollection.cs
- Int32.cs
- ParserStreamGeometryContext.cs
- NotifyInputEventArgs.cs
- ChangesetResponse.cs
- WorkflowInstanceQuery.cs
- InvariantComparer.cs
- XmlAnyElementAttributes.cs
- TextTrailingWordEllipsis.cs
- ToolboxItemFilterAttribute.cs
- CustomValidator.cs
- XmlDictionaryString.cs
- CurrentChangingEventArgs.cs
- InstanceData.cs
- mediaeventargs.cs
- DbProviderManifest.cs
- columnmapfactory.cs
- KerberosSecurityTokenAuthenticator.cs
- InputLanguage.cs
- BitmapEffectDrawingContextWalker.cs
- HttpListenerPrefixCollection.cs
- TreeNodeBindingCollection.cs
- UserPreferenceChangedEventArgs.cs
- WebPart.cs
- AggregateNode.cs
- ReliabilityContractAttribute.cs
- XmlRawWriter.cs
- WorkflowOperationBehavior.cs
- DocumentSchemaValidator.cs
- SrgsElementFactory.cs
- DesigntimeLicenseContext.cs
- BCLDebug.cs
- RSAPKCS1KeyExchangeDeformatter.cs
- MimeTypeMapper.cs
- PropertyPanel.cs
- ListSortDescriptionCollection.cs
- PathFigureCollectionConverter.cs
- DocumentPageViewAutomationPeer.cs
- MouseEventArgs.cs
- XmlSchemaSimpleTypeRestriction.cs
- Freezable.cs
- ListViewItem.cs
- ZipIOExtraFieldPaddingElement.cs
- DataGridViewAutoSizeModeEventArgs.cs
- MetaChildrenColumn.cs
- PropertyPath.cs
- FrameworkTextComposition.cs
- AnimationLayer.cs
- ProcessHostMapPath.cs
- CodeChecksumPragma.cs
- ListCollectionView.cs
- HashSetDebugView.cs
- DesignerValidatorAdapter.cs
- ProgressPage.cs
- CFStream.cs
- QueryExpression.cs
- XPathPatternBuilder.cs
- NetTcpBinding.cs
- ExpressionLexer.cs
- SamlEvidence.cs
- RunWorkerCompletedEventArgs.cs
- SignatureResourceHelper.cs
- WebPartTracker.cs
- CanExpandCollapseAllConverter.cs
- SyndicationElementExtension.cs
- DesignTimeTemplateParser.cs
- SingleObjectCollection.cs
- DatasetMethodGenerator.cs
- BamlBinaryWriter.cs
- TextPenaltyModule.cs
- PerformanceCounterPermissionEntry.cs
- XmlILModule.cs