Esempio n. 1
0
        private Type GetTypeDescriptor(IEvaluationContext context, object target, string name)
        {
            var type = target is Type type1 ? type1 : target.GetType();

            if (type.IsArray && name.Equals("Length"))
            {
                return(typeof(int));
            }

            var cacheKey = new PropertyCacheKey(type, name, target is Type);

            _typeDescriptorCache.TryGetValue(cacheKey, out var typeDescriptor);
            if (typeDescriptor == null)
            {
                // Attempt to populate the cache entry
                try
                {
                    if (CanRead(context, target, name) || CanWrite(context, target, name))
                    {
                        _typeDescriptorCache.TryGetValue(cacheKey, out typeDescriptor);
                    }
                }
                catch (AccessException ex)
                {
                    // Continue with null type descriptor
                }
            }

            return(typeDescriptor);
        }
Esempio n. 2
0
        public bool CanRead(IEvaluationContext context, object target, string name)
        {
            if (target == null)
            {
                return(false);
            }

            var type = target is Type ? (Type)target : target.GetType();

            if (type.IsArray && name.Equals("Length"))
            {
                return(true);
            }

            var cacheKey = new PropertyCacheKey(type, name, target is Type);

            if (_readerCache.ContainsKey(cacheKey))
            {
                return(true);
            }

            var method = FindGetterForProperty(name, type, target);

            if (method != null)
            {
                // Treat it like a property...
                // The readerCache will only contain gettable properties (let's not worry about setters for now).
                var typeDescriptor = method.ReturnType;
                method = ClassUtils.GetInterfaceMethodIfPossible(method);
                _readerCache[cacheKey]         = new InvokerPair(method, typeDescriptor);
                _typeDescriptorCache[cacheKey] = typeDescriptor;
                return(true);
            }
            else
            {
                var field = FindField(name, type, target);
                if (field != null)
                {
                    var typeDescriptor = field.FieldType;
                    _readerCache[cacheKey]         = new InvokerPair(field, typeDescriptor);
                    _typeDescriptorCache[cacheKey] = typeDescriptor;
                    return(true);
                }
            }

            return(false);
        }
Esempio n. 3
0
        public bool CanWrite(IEvaluationContext context, object target, string name)
        {
            if (!_allowWrite || target == null)
            {
                return(false);
            }

            var type     = target is Type ? (Type)target : target.GetType();
            var cacheKey = new PropertyCacheKey(type, name, target is Type);

            if (_writerCache.ContainsKey(cacheKey))
            {
                return(true);
            }

            var method = FindSetterForProperty(name, type, target);

            if (method != null)
            {
                // Treat it like a property
                var typeDescriptor = method.GetParameters()[0].ParameterType;
                method = ClassUtils.GetInterfaceMethodIfPossible(method);
                _writerCache[cacheKey]         = method;
                _typeDescriptorCache[cacheKey] = typeDescriptor;
                return(true);
            }
            else
            {
                var field = FindField(name, type, target);
                if (field != null)
                {
                    _writerCache[cacheKey]         = field;
                    _typeDescriptorCache[cacheKey] = field.FieldType;
                    return(true);
                }
            }

            return(false);
        }
Esempio n. 4
0
        public ITypedValue Read(IEvaluationContext context, object target, string name)
        {
            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }

            var type = target is Type ? (Type)target : target.GetType();

            if (type.IsArray && name.Equals("Length"))
            {
                if (target is Type)
                {
                    throw new AccessException("Cannot access length on array class itself");
                }

                var asArray = (Array)target;
                return(new TypedValue(asArray.GetLength(0)));
            }

            var cacheKey = new PropertyCacheKey(type, name, target is Type);

            _readerCache.TryGetValue(cacheKey, out var invoker);
            _lastReadInvokerPair = invoker;

            if (invoker == null || invoker.Member is MethodInfo)
            {
                var method = (MethodInfo)(invoker != null ? invoker.Member : null);
                if (method == null)
                {
                    method = FindGetterForProperty(name, type, target);
                    if (method != null)
                    {
                        // Treat it like a property...
                        // The readerCache will only contain gettable properties (let's not worry about setters for now).
                        var typeDescriptor = method.ReturnType;
                        method  = ClassUtils.GetInterfaceMethodIfPossible(method);
                        invoker = new InvokerPair(method, typeDescriptor);
                        _lastReadInvokerPair   = invoker;
                        _readerCache[cacheKey] = invoker;
                    }
                }

                if (method != null)
                {
                    try
                    {
                        var value = method.Invoke(target, new object[0]);
                        return(new TypedValue(value, value != null ? value.GetType() : invoker.TypeDescriptor));
                    }
                    catch (Exception ex)
                    {
                        throw new AccessException("Unable to access property '" + name + "' through getter method", ex);
                    }
                }
            }

            if (invoker == null || invoker.Member is FieldInfo)
            {
                var field = (FieldInfo)(invoker == null ? null : invoker.Member);
                if (field == null)
                {
                    field = FindField(name, type, target);
                    if (field != null)
                    {
                        invoker = new InvokerPair(field, field.FieldType);
                        _lastReadInvokerPair   = invoker;
                        _readerCache[cacheKey] = invoker;
                    }
                }

                if (field != null)
                {
                    try
                    {
                        var value = field.GetValue(target);
                        return(new TypedValue(value, value != null ? value.GetType() : invoker.TypeDescriptor));
                    }
                    catch (Exception ex)
                    {
                        throw new AccessException("Unable to access field '" + name + "'", ex);
                    }
                }
            }

            throw new AccessException("Neither getter method nor field found for property '" + name + "'");
        }
Esempio n. 5
0
        public IPropertyAccessor CreateOptimalAccessor(IEvaluationContext context, object target, string name)
        {
            // Don't be clever for arrays or a null target...
            if (target == null)
            {
                return(this);
            }

            var clazz = target is Type ? (Type)target : target.GetType();

            if (clazz.IsArray)
            {
                return(this);
            }

            var cacheKey = new PropertyCacheKey(clazz, name, target is Type);

            _readerCache.TryGetValue(cacheKey, out var invocationTarget);

            if (invocationTarget == null || invocationTarget.Member is MethodInfo)
            {
                var method = (MethodInfo)invocationTarget?.Member;
                if (method == null)
                {
                    method = FindGetterForProperty(name, clazz, target);
                    if (method != null)
                    {
                        var typeDescriptor = method.ReturnType;
                        method                 = ClassUtils.GetInterfaceMethodIfPossible(method);
                        invocationTarget       = new InvokerPair(method, typeDescriptor);
                        _readerCache[cacheKey] = invocationTarget;
                    }
                }

                if (method != null)
                {
                    return(new OptimalPropertyAccessor(invocationTarget));
                }
            }

            if (invocationTarget == null || invocationTarget.Member is FieldInfo)
            {
                var field = invocationTarget != null ? (FieldInfo)invocationTarget.Member : null;
                if (field == null)
                {
                    field = FindField(name, clazz, target is Type);
                    if (field != null)
                    {
                        invocationTarget       = new InvokerPair(field, field.FieldType);
                        _readerCache[cacheKey] = invocationTarget;
                    }
                }

                if (field != null)
                {
                    return(new OptimalPropertyAccessor(invocationTarget));
                }
            }

            return(this);
        }
Esempio n. 6
0
        public void Write(IEvaluationContext context, object target, string name, object newValue)
        {
            if (!_allowWrite)
            {
                throw new AccessException("PropertyAccessor for property '" + name + "' on target [" + target + "] does not allow write operations");
            }

            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }

            var type = target is Type ? (Type)target : target.GetType();

            var possiblyConvertedNewValue = newValue;
            var typeDescriptor            = GetTypeDescriptor(context, target, name);

            if (typeDescriptor != null)
            {
                try
                {
                    possiblyConvertedNewValue = context.TypeConverter.ConvertValue(newValue, newValue?.GetType(), typeDescriptor);
                }
                catch (EvaluationException evaluationException)
                {
                    throw new AccessException("Type conversion failure", evaluationException);
                }
            }

            var cacheKey = new PropertyCacheKey(type, name, target is Type);

            _writerCache.TryGetValue(cacheKey, out var cachedMember);

            if (cachedMember == null || cachedMember is MethodInfo)
            {
                var method = (MethodInfo)cachedMember;
                if (method == null)
                {
                    method = FindSetterForProperty(name, type, target);
                    if (method != null)
                    {
                        method                 = ClassUtils.GetInterfaceMethodIfPossible(method);
                        cachedMember           = method;
                        _writerCache[cacheKey] = cachedMember;
                    }
                }

                if (method != null)
                {
                    try
                    {
                        method.Invoke(target, new object[] { possiblyConvertedNewValue });
                        return;
                    }
                    catch (Exception ex)
                    {
                        throw new AccessException("Unable to access property '" + name + "' through setter method", ex);
                    }
                }
            }

            if (cachedMember == null || cachedMember is FieldInfo)
            {
                var field = (FieldInfo)cachedMember;
                if (field == null)
                {
                    field = FindField(name, type, target);
                    if (field != null)
                    {
                        cachedMember           = field;
                        _writerCache[cacheKey] = cachedMember;
                    }
                }

                if (field != null)
                {
                    try
                    {
                        field.SetValue(target, possiblyConvertedNewValue);
                        return;
                    }
                    catch (Exception ex)
                    {
                        throw new AccessException("Unable to access field '" + name + "'", ex);
                    }
                }
            }

            throw new AccessException("Neither setter method nor field found for property '" + name + "'");
        }