File: System\Activities\XamlIntegration\TypeConverterBase.cs
Project: ndp\cdf\src\NetFx40\System.Activities\System.Activities.csproj (System.Activities)
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
 
namespace System.Activities.XamlIntegration
{
    using System;
    using System.Collections.Concurrent;
    using System.ComponentModel;
    using System.Globalization;
    using System.Runtime;
    using System.Threading;
    using System.Xaml;
 
    public abstract class TypeConverterBase : TypeConverter
    {
        // Give the Lazy<T> a Func<T> to create the ConcurrentDictionary<Type, TypeConverterHelper> because TypeConverterHelper is
        // internal and we want to avoid the demand for ReflectionPermission(MemberAccess).
        Lazy<ConcurrentDictionary<Type, TypeConverterHelper>> helpers = new Lazy<ConcurrentDictionary<Type, TypeConverterHelper>>( delegate()
                        {
                            return new ConcurrentDictionary<Type, TypeConverterHelper>();
                        }
                    );
 
        TypeConverterHelper helper;
        Type baseType;
        Type helperType;
 
        internal TypeConverterBase(Type baseType, Type helperType)
        {
            this.baseType = baseType;
            this.helperType = helperType;
        }
 
        internal TypeConverterBase(Type targetType, Type baseType, Type helperType)
        {
            this.helper = GetTypeConverterHelper(targetType, baseType, helperType);
        }
 
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            if (sourceType == TypeHelper.StringType)
            {
                return true;
            }
 
            return base.CanConvertFrom(context, sourceType);
        }
 
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            if (destinationType == TypeHelper.StringType)
            {
                return false;
            }
            return base.CanConvertTo(context, destinationType);
        }
 
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            string stringValue = value as string;
            if (stringValue != null)
            {
                TypeConverterHelper currentHelper = helper;
                if (currentHelper == null)
                {
                    IDestinationTypeProvider targetService = context.GetService(typeof(IDestinationTypeProvider)) as IDestinationTypeProvider;
                    Type targetType = targetService.GetDestinationType();
 
                    if (!this.helpers.Value.TryGetValue(targetType, out currentHelper))
                    {
                        currentHelper = GetTypeConverterHelper(targetType, this.baseType, this.helperType);
                        if (!this.helpers.Value.TryAdd(targetType, currentHelper))
                        {
                            if (!this.helpers.Value.TryGetValue(targetType, out currentHelper))
                            {
                                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.TypeConverterHelperCacheAddFailed(targetType)));
                            }
                        }
                    }
                }
                object result = currentHelper.UntypedConvertFromString(stringValue, context);
                return result;
            }
 
            return base.ConvertFrom(context, culture, value);
        }
 
        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            return base.ConvertTo(context, culture, value, destinationType);
        }
 
        TypeConverterHelper GetTypeConverterHelper(Type targetType, Type baseType, Type helperType)
        {
            Type[] genericTypeArguments;
            if (baseType.BaseType == targetType)
            {
                // support non-generic ActivityWithResult, In/Out/InOutArgument 
                genericTypeArguments = new Type[] { TypeHelper.ObjectType };
            }
            else
            {
                // Find baseType in the base class list of targetType
                while (!targetType.IsGenericType ||
                    !(targetType.GetGenericTypeDefinition() == baseType))
                {
                    if (targetType == TypeHelper.ObjectType)
                    {
                        throw FxTrace.Exception.AsError(new InvalidOperationException(SR.InvalidTypeConverterUsage));
                    }
 
                    targetType = targetType.BaseType;
                }
                genericTypeArguments = targetType.GetGenericArguments();
            }
 
            Type concreteHelperType = helperType.MakeGenericType(genericTypeArguments);
            return (TypeConverterHelper)Activator.CreateInstance(concreteHelperType);
        }
 
        internal abstract class TypeConverterHelper
        {
            public abstract object UntypedConvertFromString(string text, ITypeDescriptorContext context);
 
            public static T GetService<T>(ITypeDescriptorContext context) where T : class
            {
                T service = (T)context.GetService(typeof(T));
                if (service == null)
                {
                    throw FxTrace.Exception.AsError(new InvalidOperationException(SR.InvalidTypeConverterUsage));
                }
 
                return service;
            }
        }
 
        internal abstract class TypeConverterHelper<T> : TypeConverterHelper
        {
            public abstract T ConvertFromString(string text, ITypeDescriptorContext context);
 
            public sealed override object UntypedConvertFromString(string text, ITypeDescriptorContext context)
            {
                return ConvertFromString(text, context);
            }
        }
    }
}