File: AuthoringOM\Serializer\CodeTypeReferenceSerializer.cs
Project: ndp\cdf\src\WF\Common\System.Workflow.ComponentModel.csproj (System.Workflow.ComponentModel)
using System;
using System.CodeDom;
using System.Text;
using System.Workflow.ComponentModel.Compiler;
using System.Globalization;
 
namespace System.Workflow.ComponentModel.Serialization
{
    /// <summary>
    /// This class serializes and deserializes CodeTypeReference objects used by rules.
    /// It saves the AssemblyQualifiedName, so that the type can be loaded if the assembly is not
    /// previously loaded at run-time.
    /// </summary>
    internal sealed class CodeTypeReferenceSerializer : WorkflowMarkupSerializer
    {
        // this must match the name used by rules (RuleUserDataKeys.QualifiedName)
        internal const string QualifiedName = "QualifiedName";
 
        protected internal override bool CanSerializeToString(WorkflowMarkupSerializationManager serializationManager, object value)
        {
            return (value is CodeTypeReference);
        }
 
        protected internal override string SerializeToString(WorkflowMarkupSerializationManager serializationManager, object value)
        {
            if (serializationManager == null)
                throw new ArgumentNullException("serializationManager");
            if (value == null)
                throw new ArgumentNullException("value");
 
            CodeTypeReference reference = value as CodeTypeReference;
            if (reference == null)
                return string.Empty;
 
            // make the typename as best we can, and try to get the fully qualified name
            // if a type is used in an assembly not referenced, GetType will complain
            string typeName = ConvertTypeReferenceToString(reference);
            Type type = serializationManager.GetType(typeName);
            if (type == null)
            {
                // TypeProvider can't find it, see if it's a common type in mscorlib
                type = Type.GetType(typeName, false);
                if (type == null)
                {
                    // still no luck finding it, so simply save the name without assembly information
                    // this is equivalent to what happened before
                    return typeName;
                }
            }
            //
            // If we get a real type make sure that we get the correct fully qualified name for the target framework version
            string assemblyFullName = null;
            TypeProvider typeProvider = serializationManager.GetService(typeof(ITypeProvider)) as TypeProvider;
            if (typeProvider != null)
            {
                assemblyFullName = typeProvider.GetAssemblyName(type);
            }
            //
            // If we didn't find an assembly value it is either a local type or something is wrong
            // However per the general guidance on multi-targeting it is up to the caller
            // to make sure that writers (such as Xoml) are given types that exist in the target framework
            // This makes it the job of the rules designer or rules validator to not call the Xoml stack
            // with types that do not exist in the target framework
            if (string.IsNullOrEmpty(assemblyFullName))
            {
                typeName = type.AssemblyQualifiedName;
            }
            else
            {
                typeName = string.Format(CultureInfo.InvariantCulture, "{0}, {1}", type.FullName, assemblyFullName);
            }
            return typeName;
        }
 
        protected internal override object DeserializeFromString(WorkflowMarkupSerializationManager serializationManager, Type propertyType, string value)
        {
            if (!propertyType.IsAssignableFrom(typeof(CodeTypeReference)))
                return null;
 
            // if the string is empty or markup extension,
            // then the object is null
            if (string.IsNullOrEmpty(value) || IsValidCompactAttributeFormat(value))
                return null;
 
            // value is the fully qualified name of the type
            // however, it may refer to non-existant assemblies, so we may get an error
            CodeTypeReference result;
            try
            {
                Type type = serializationManager.GetType(value);
                if (type != null)
                {
                    result = new CodeTypeReference(type);
                    result.UserData[QualifiedName] = type.AssemblyQualifiedName;
                    return result;
                }
            }
            catch (Exception)
            {
                // something went wrong getting the type, so simply pass in the string and
                // let CodeTypeReference figure it out. Note that CodeTypeReference has a method
                // RipOffAssemblyInformationFromTypeName, so assembly names are ignored.
            }
            result = new CodeTypeReference(value);
            result.UserData[QualifiedName] = value;
            return result;
        }
 
        private static string ConvertTypeReferenceToString(CodeTypeReference reference)
        {
            // CodeTypeReferences are nested structures that represent a type.
            // This code converts one into a string that GetType() should like.
 
            StringBuilder result;
            if (reference.ArrayElementType != null)
            {
                // type represents an array
                result = new StringBuilder(ConvertTypeReferenceToString(reference.ArrayElementType));
                if (reference.ArrayRank > 0)
                {
                    result.Append("[");
                    result.Append(',', reference.ArrayRank - 1);
                    result.Append("]");
                }
            }
            else
            {
                // type is not an array, but may have type arguments
                result = new StringBuilder(reference.BaseType);
                if ((reference.TypeArguments != null) && (reference.TypeArguments.Count > 0))
                {
                    string prefix = "[";
                    foreach (CodeTypeReference nested in reference.TypeArguments)
                    {
                        result.Append(prefix);
                        result.Append(ConvertTypeReferenceToString(nested));
                        prefix = ", ";
                    }
                    result.Append("]");
                }
            }
            return result.ToString();
        }
    }
}