private static Type GetIDictionaryType(MapTypeContext context)
 {
     return(context.TargetType.GetInterfaces()
            .Where(i => i.IsGenericType)
            .FirstOrDefault(i => i.GetGenericTypeDefinition() == typeof(IDictionary <,>) && i.GenericTypeArguments[0] == typeof(string))
            ?? throw MapCompilerException.InvalidDictionaryTargetType(context.TargetType));
 }
Exemplo n.º 2
0
 public ScalarCompiler(IEnumerable <IScalarMapCompiler> scalarCompilers)
 {
     _scalarCompilers = scalarCompilers.ToList();
     if (_scalarCompilers.Count == 0)
     {
         throw MapCompilerException.NoScalarMapCompilers();
     }
 }
        private ConcreteCollectionInfo GetTypeInfo(MapTypeContext context)
        {
            var targetType   = context.TargetType;
            var typeSettings = context.Settings.GetTypeSettings(targetType);

            if (typeSettings.BaseType != typeof(object))
            {
                targetType = typeSettings.GetDefault().Type;
            }

            // We absolutely need a constructor here, there's no way around it. The user has asked
            // for a specific concrete type, we can either return that type or the configured
            // subclass, but we can't default to something else with a parameterless constructor
            var constructor = targetType.GetConstructor(Type.EmptyTypes);

            if (constructor == null)
            {
                throw MapCompilerException.InvalidCollectionType(targetType);
            }

            // Same with .Add(). The type absolutely must have a .Add(T) method variant or we
            // cannot proceed
            var addMethods = targetType
                             .GetMethods(BindingFlags.Public | BindingFlags.Instance)
                             .Where(m => m.Name == AddMethodName && m.GetParameters().Length == 1)
                             .ToList();

            if (addMethods.Count == 0)
            {
                throw MapCompilerException.InvalidCollectionType(targetType);
            }

            // Find all IEnumerable<T> interfaces. For each one we're going to look for a matching
            // .Add(T) method. If we find a match, that's what we're going with.
            var iEnumerableOfTTypes = targetType
                                      .GetInterfaces()
                                      .Where(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable <>))
                                      .ToDictionary(t => t.GetGenericArguments()[0]);

            if (iEnumerableOfTTypes.Count > 0)
            {
                var bestAddMethod = addMethods.FirstOrDefault(m => iEnumerableOfTTypes.ContainsKey(m.GetParameters()[0].ParameterType));
                if (bestAddMethod != null)
                {
                    var bestAddElementType = bestAddMethod.GetParameters()[0].ParameterType;
                    return(new ConcreteCollectionInfo(targetType, bestAddElementType, constructor, bestAddMethod));
                }
            }

            // At this point we know the collection must be IEnumerable because of precondition
            // checks. So we'll just use any available Add method
            var addMethod   = addMethods.FirstOrDefault();
            var elementType = addMethod.GetParameters()[0].ParameterType;

            return(new ConcreteCollectionInfo(targetType, elementType, constructor, addMethod));
        }
 private static ConstructorInfo GetDictionaryConstructor(Type targetType)
 {
     return(targetType.GetConstructor(Type.EmptyTypes) ?? throw MapCompilerException.InvalidDictionaryTargetType(targetType));
 }
 private static MethodInfo GetIDictionaryAddMethod(Type targetType, Type idictType)
 {
     return(idictType.GetMethod(nameof(IDictionary <string, object> .Add)) ?? throw MapCompilerException.InvalidDictionaryTargetType(targetType));
 }