public Expression GetValue(Expression element, FieldInfo field) { var type = field.FieldType; if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(RefObject <>)) { return(ElementBinder.BuildContainerInstantiation(type, element, Expression.Constant(field.Name), _initialValue)); } throw new ArgumentException($"Field {field} of {field.DeclaringType} must be a type of {typeof(RefObject<>)}"); }
public Expression GetValue(Expression element, ParameterInfo parameter) { var type = parameter.ParameterType; if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(RefObject <>)) { return(ElementBinder.BuildContainerInstantiation(type, element, Expression.Constant(parameter.Name), _initialValue)); } // todo: this breaks with aot return(ElementBinder.BuildContainerValueAccess(ElementBinder.BuildContainerInstantiation(typeof(RefObject <>).MakeGenericType(type), element, Expression.Constant(parameter.Name), _initialValue))); }
public Expression Build(Expression element, MethodInfo method) { var type = method.DeclaringType; if (method.ReturnType != typeof(void) && method.ReturnType != typeof(EffectCleanupDelegate)) { throw new ArgumentException($"Effect method {method} in {type} returns unsupported type {method.ReturnType}. It must return either void or {nameof(EffectCleanupDelegate)}."); } // find dependency fields var fields = new FieldInfo[_depFields.Length]; for (var i = 0; i < _depFields.Length; i++) { fields[i] = type?.GetAllField(_depFields[i]) ?? throw new ArgumentException($"Cannot find field '{_depFields[i]}' in {type}."); } // find parameter providers var parameters = method.GetParameters(); var arguments = new Expression[parameters.Length]; for (var i = 0; i < parameters.Length; i++) { arguments[i] = parameters[i].GetCustomAttributes().OfType <IBinderMethodParameterProvider>().FirstOrDefault()?.GetValue(element, parameters[i]) ?? throw new ArgumentException($"No provider configured for parameter {parameters} of method {method} in {type}."); } var body = new List <Expression>(); // build dependency array var deps = Expression.Variable(typeof(object[]), "deps"); if (Once) { body.Add(Expression.Assign(deps, Expression.Constant(null, typeof(object[])))); } else { var items = new Expression[fields.Length + arguments.Length]; for (var i = 0; i < fields.Length; i++) { items[i] = Expression.Field(element, fields[i]); } for (var i = 0; i < arguments.Length; i++) { items[fields.Length + i] = arguments[i]; } body.Add(Expression.Assign(deps, Expression.NewArrayInit(typeof(object), items.Select(x => Expression.Convert(x, typeof(object)))))); } // create effect info var effect = Expression.Variable(typeof(RefObject <EffectInfo>), "effectObj"); body.Add(Expression.Assign(effect, ElementBinder.BuildContainerInstantiation(typeof(RefObject <EffectInfo>), element, Expression.Constant($"effect:{method.Name}"), null))); // call effect set method body.Add(Expression.Call( Expression.Coalesce( ElementBinder.BuildContainerValueAccess(effect), Expression.Assign(ElementBinder.BuildContainerValueAccess(effect), Expression.New(typeof(EffectInfo)))), _effectInfoSetMethod, ElementBinder.BuildElementNodeAccess(element), Expression.Lambda <EffectDelegate>(buildEffect()), deps)); Expression buildEffect() { var result = Expression.Call(element, method, arguments); if (method.ReturnType == typeof(EffectCleanupDelegate)) { return(result); } return(Expression.Block(result, Expression.Constant(null, typeof(EffectCleanupDelegate)))); } return(Expression.Block(new[] { deps, effect }, body)); }