/// <summary> /// Invokes proxy methods which return a value. /// </summary> /// <typeparam name="T">The return type of the method being invoked.</typeparam> /// <param name="args">The arguments to pass to the method.</param> /// <returns>The return value of the default proxy method.</returns> /// <remarks>This method will invoke methods on all of the proxy objects, but will return /// the result of the invocation on the default object. /// </remarks> protected T ProxyInvoke <T>(params object[] args) { if (objects.Count == 0) { return(default(T)); } StackTrace trace = new StackTrace(); StackFrame frame = trace.GetFrame(1); MethodInfo method = frame.GetMethod() as MethodInfo; ProxyAttributeCollection attributes = GetAttributes(method); bool first = true; T result = default(T); foreach (object invoke in objects) { ProxyTypeBindingAttribute binding = attributes.GetTypeBinding(invoke); MemberInfoAccessor accessor = binding.GetTargetAccessor(typeof(T), args); if (first) { result = (T)accessor.Get(invoke, args); first = false; } else { accessor.Get(invoke, args); } } return(result); }
/// <summary> /// Gets the accessor object that can be used to invoke the method, field, or property on the type of object with the /// given return value and arguments. /// </summary> /// <param name="returnType">The return type of the method, field, or property.</param> /// <param name="arguments">The arguments passed to the method, field, or property.</param> /// <returns>An object which can be used to invoke the member that matches the given name, return type, /// and arguments. /// </returns> public MemberInfoAccessor GetTargetAccessor(Type returnType, object[] arguments) { // get an array of members MemberInfo[] members = Type.GetMember(TargetName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); // look for the member that will fit the caller foreach (MemberInfo member in members) { if (member.MemberType == MemberTypes.Property) { PropertyInfo propertyInfo = member as PropertyInfo; MethodInfo propertyGetMethod = propertyInfo.GetGetMethod(true); if (MemberInfoAccessor.VerifyMatch(propertyGetMethod, returnType, arguments)) { return(MemberInfoAccessor.BindMember(propertyGetMethod)); } MethodInfo propertySetMethod = propertyInfo.GetSetMethod(true); if (MemberInfoAccessor.VerifyMatch(propertySetMethod, returnType, arguments)) { return(MemberInfoAccessor.BindMember(propertySetMethod)); } } else if (member.MemberType == MemberTypes.Field) { FieldInfo fieldInfo = member as FieldInfo; if ((returnType == fieldInfo.FieldType && arguments.Length == 0)) { return(MemberInfoAccessor.BindMember(fieldInfo)); } if (returnType == typeof(void) && arguments.Length == 1 && arguments[0].GetType().IsAssignableFrom(fieldInfo.FieldType)) { return(MemberInfoAccessor.BindMember(fieldInfo)); } } else if (member.MemberType == MemberTypes.Method) { MethodInfo methodInfo = member as MethodInfo; if (MemberInfoAccessor.VerifyMatch(methodInfo, returnType, arguments)) { return(MemberInfoAccessor.BindMember(methodInfo)); } } } throw new MissingProxyTargetException(); }
/// <summary> /// Performs the get operation on the first object in the list of proxy objects (the default object). /// </summary> /// <typeparam name="T">The type to cast the return value as.</typeparam> /// <param name="args">The indices to pass to the get method.</param> /// <returns>The result of executing a get operation on the default proxy object, or the default value of T /// if there are no proxy objects. /// </returns> public T ProxyGet <T>(params object[] args) { if (objects.Count == 0) { return(default(T)); } StackTrace trace = new StackTrace(); StackFrame frame = trace.GetFrame(1); MethodInfo method = frame.GetMethod() as MethodInfo; ProxyAttributeCollection attributes = GetAttributes(method); ProxyTypeBindingAttribute binding = attributes.GetTypeBinding(objects[0]); MemberInfoAccessor accessor = binding.GetTargetAccessor(typeof(T), args); return((T)accessor.Get(objects[0], args)); }
/// <summary> /// Gets the attribute that should be used for a given object instance. /// </summary> /// <param name="instance">The object instance that is going to be invoked by /// this method stub.</param> /// <returns>The attributes governing the invocation of methods on the instance object.</returns> /// <remarks> /// This method returns the best match attribute for the instance object. For example, if the object /// instance is of type TextBox, and the list of bindings contains entries for the TextBoxBase and the /// Control classes, then the attributes for the TextBoxBase would be used for this object, since /// TextBoxBase is closer to TextBox in the inheritance hierarchy than Control. /// </remarks> public ProxyTypeBindingAttribute GetTypeBinding(object instance) { // get the instance of the type to get the attributes for Type instanceType = instance.GetType(); // if the type is already here, return it if (typeBindings.ContainsKey(instanceType)) { return(typeBindings[instanceType]); } // look for the correct type, which is the type in the list that is closest to the instance type in the inheritance hierarcy Type correctType = null; foreach (Type type in typeBindings.Keys) { if (type.IsAssignableFrom(instanceType) && (correctType == null || correctType.IsAssignableFrom(type))) { correctType = type; } } // if no types are in the inheritance hierarchy, use the instance type if (correctType == null) { correctType = instanceType; } // if the type isn't in the list, assume that the method/property/field has the same name if (!typeBindings.ContainsKey(correctType)) { if (MemberInfoAccessor.IsGetMethod(Method) || MemberInfoAccessor.IsSetMethod(Method)) { typeBindings.Add(correctType, new ProxyTypeBindingAttribute(correctType, MemberInfoAccessor.GetProperty(Method).Name)); } else { typeBindings.Add(correctType, new ProxyTypeBindingAttribute(correctType, Method.Name)); } } return(typeBindings[correctType]); }
/// <summary> /// Invokes proxy methods which do not return a value. /// </summary> /// <param name="args">The arguments to pass to the method.</param> protected void ProxyInvoke(params object[] args) { if (objects.Count == 0) { return; } StackTrace trace = new StackTrace(); StackFrame frame = trace.GetFrame(1); MethodInfo method = frame.GetMethod() as MethodInfo; ProxyAttributeCollection attributes = GetAttributes(method); foreach (object invoke in objects) { ProxyTypeBindingAttribute binding = attributes.GetTypeBinding(invoke); MemberInfoAccessor accessor = binding.GetTargetAccessor(typeof(void), args); accessor.Get(invoke, args); } }
/// <summary> /// Performs the set operation on all proxy objects. /// </summary> /// <param name="value">The value to set on the proxy objects.</param> /// <param name="args">The indices of the set operation.</param> protected void ProxySet(object value, params object[] args) { if (objects.Count == 0) { return; } StackTrace trace = new StackTrace(); StackFrame frame = trace.GetFrame(1); MethodInfo method = frame.GetMethod() as MethodInfo; ProxyAttributeCollection attributes = GetAttributes(method); foreach (object invoke in objects) { ProxyTypeBindingAttribute binding = attributes.GetTypeBinding(invoke); object[] argsWithValue = new object[args.Length + 1]; argsWithValue[0] = value; Array.Copy(args, 0, argsWithValue, 1, args.Length); MemberInfoAccessor accessor = binding.GetTargetAccessor(typeof(void), argsWithValue); accessor.Set(invoke, value, args); } }
/// <summary> /// Performs reflection on a method in order to determine which methods on proxy objects /// the method stub is bound to. /// </summary> /// <param name="method">The method to reflect over.</param> /// <returns>The collection of attributes about the method.</returns> private ProxyAttributeCollection ReflectMethod(MethodInfo method) { ProxyAttributeCollection collection = new ProxyAttributeCollection(method); // get the information that is applied directly to the method object[] typeBindings = method.GetCustomAttributes(typeof(ProxyTypeBindingAttribute), true); foreach (ProxyTypeBindingAttribute attribute in typeBindings) { collection.AddTypeBinding(attribute); } // if the method is a get or set method on a property, also get the attributes applied to the property if (MemberInfoAccessor.IsGetMethod(method) || MemberInfoAccessor.IsSetMethod(method)) { PropertyInfo propertyInfo = MemberInfoAccessor.GetProperty(method); object[] moreBindings = propertyInfo.GetCustomAttributes(typeof(ProxyTypeBindingAttribute), true); foreach (ProxyTypeBindingAttribute attribute in moreBindings) { collection.AddTypeBinding(attribute); } } return(collection); }