ProxyManager

Abstract

The ProxyManager is used to create and configure proxy classes. The ProxyManager is the main class used in BeanProxy. The ProxyManager uses Builder to create a dynamic runtime child class of the class-under-test. Every overridable is overriden. Events are even given a back door; see GetEvent

Every overriden (proxied) method in the proxy is also given a configuration. The GetMethodConfig, GetAction, GetFunc, LookupAction, and LookupFunc function groups give access to those configurations.

Useful Functions

CreateProxy<T>

Returns a proxy instance of a given template type. The template type must not be sealed, static, or internal to an assembly not in the same dll. This method is typically the first method called in a test.
public class MyClass
{
}

//tests
public void MyClassTest()
{
  var proxy = ProxyManager.CreateProxy<MyClass>();
  //...
}

GetMethodConfig

Returns the configuration for the given method.
public abstract class MyClass
{
  public abstract void Foo();
}

//tests
public void MyClassTest()
{
  var proxy = ProxyManager.CreateProxy<MyClass>();
  var fooConfig = ProxyManager.GetMethodConfig((Action)proxy.Foo);
  //...
}
This example shows the use of GetMethodConfig to get a configuration for an Action. There are specially designed Get* methods for both Actions and Funcs from 0 to 5 parameters. GetMethodConfig works with any type of method, but is exposed for use moreso to allow the user to get methods that do not follow the basic prototypes. Consider:
public abstract class MyClass
{
  public abstract void Foo(ref int i);
}
//tests
public delegate void ActionRef<T>(ref T i);
public void MyClassTest()
{
  var proxy = ProxyManager.CreateProxy<MyClass>();
  var fooConfig = ProxyManager.GetMethodConfig((ActionRef<int>)proxy.Foo);
  //...
}
Because ref and out are not supported in the predefined Get* methods, GetMethodConfig is needed as seen above. GetMethodConfig works for any of the predefined cases, as well as the extra cases as with ref and out. GetMethodConfig returns the exact same configuration object as the predefined Get* methods return when specifying the same function.

GetAction

This template function group simplifies GetMethodConfig without needing to explicitly declare the delegate type. Actions are void return types, as per the pattern with System.Action. GetAction, as well as GetFunc, uses a template parameter to specify parameter types.
public abstract class MyClass
{
  public abstract void Foo();
  public abstract void Foo(int a);
  public abstract void Foo(int a, string b);
  public abstract void Foo(int a, string b, double c);
  public abstract void Foo(int a, string b, double c, byte d);
  public abstract void Foo(int a, string b, double c, byte d, bool e);
}
//tests
public void MyClassTest()
{
  var proxy = ProxyManager.CreateProxy<MyClass>();
  var foo0Config = ProxyManager.GetAction(proxy.Foo);
  var foo1Config = ProxyManager.GetAction<int>(proxy.Foo);
  var foo2Config = ProxyManager.GetAction<int, string>(proxy.Foo);
  var foo3Config = ProxyManager.GetAction<int, string, double>(proxy.Foo);
  var foo4Config = ProxyManager.GetAction<int, string, double, byte>(proxy.Foo);
  var foo5Config = ProxyManager.GetAction<int, string, double, byte, bool>(proxy.Foo);
  //...
}
This example demostrates the 6 predefined Actions.

GetFunc

Like GetAction methods, but for non-void return types. Note that the return type is declared last in the template parameter list (again, following the design with System.Func).
public abstract class MyClass
{
  public abstract int Foo();
  public abstract string Foo(int a);
  public abstract double Foo(int a, string b);
  public abstract float Foo(int a, string b, double c);
  public abstract bool Foo(int a, string b, double c, byte d);
  public abstract decimal Foo(int a, string b, double c, byte d, bool e);
}
//tests
public void MyClassTest()
{
  var proxy = ProxyManager.CreateProxy<MyClass>();
  var foo0Config = ProxyManager.GetFunc<int>(proxy.Foo);
  var foo1Config = ProxyManager.GetFunc<int, string>(proxy.Foo);
  var foo2Config = ProxyManager.GetFunc<int, string, double>(proxy.Foo);
  var foo3Config = ProxyManager.GetFunc<int, string, double, float>(proxy.Foo);
  var foo4Config = ProxyManager.GetFunc<int, string, double, byte, bool>(proxy.Foo);
  var foo5Config = ProxyManager.GetFunc<int, string, double, byte, bool, decimal>(proxy.Foo);
  //...
}

LookupAction

Like GetAction, but takes the name of the method as a string to allow access to protected methods. It still works for public methods just the same, but why specify a public method by string name when you can use the actual function pointer?
public abstract class MyClass
{
  protected abstract void Foo();
  protected abstract void Foo(int a);
  protected abstract void Foo(int a, string b);
  protected abstract void Foo(int a, string b, double c);
  protected abstract void Foo(int a, string b, double c, byte d);
  protected abstract void Foo(int a, string b, double c, byte d, bool e);
}
//tests
public void MyClassTest()
{
  var proxy = ProxyManager.CreateProxy<MyClass>();
  var foo0Config = ProxyManager.LookupAction(proxy, "Foo");
  var foo1Config = ProxyManager.LookupAction<int>(proxy, "Foo");
  var foo2Config = ProxyManager.LookupAction<int, string>(proxy, "Foo");
  var foo3Config = ProxyManager.LookupAction<int, string, double>(proxy, "Foo");
  var foo4Config = ProxyManager.LookupAction<int, string, double, byte>(proxy, "Foo");
  var foo5Config = ProxyManager.LookupAction<int, string, double, byte, bool>(proxy, "Foo");
  //...
}

LookupFunc

Like LookupAction but the GetFunc version (i.e. for non-void return types).
public abstract class MyClass
{
  protected abstract int Foo();
  protected abstract string Foo(int a);
  protected abstract double Foo(int a, string b);
  protected abstract float Foo(int a, string b, double c);
  protected abstract bool Foo(int a, string b, double c, byte d);
  protected abstract decimal Foo(int a, string b, double c, byte d, bool e);
}
//tests
public void MyClassTest()
{
  var proxy = ProxyManager.CreateProxy<MyClass>();
  var foo0Config = ProxyManager.LookupFunc<int>(proxy, "Foo");
  var foo1Config = ProxyManager.LookupFunc<int, string>(proxy, "Foo");
  var foo2Config = ProxyManager.LookupFunc<int, string, double>(proxy, "Foo");
  var foo3Config = ProxyManager.LookupFunc<int, string, double, float>(proxy, "Foo");
  var foo4Config = ProxyManager.LookupFunc<int, string, double, byte, bool>(proxy, "Foo");
  var foo5Config = ProxyManager.LookupFunc<int, string, double, byte, bool, decimal>(proxy, "Foo");
  //...
}

LookupMethod

The Get* and Lookup* methods allow for retrieving a method configuration with types known at compile time. However, the programmer also has the option to search for a method by using Type definitions for parameter and return types. The string name of the method must be an exact match. Each given type, either for the return type or the parameter types, have to be an exact match or null. Null implies the type is unknown or not specified. If no match is found, a KeyNotFoundException is thrown. If more than one is found, an ArgumentException is thrown. Otherwise, the MethodConfig is returned. One last rule is that the number of parameters specified must match as well. Note that the return type (which can be typeof(void)) is declared at the end, following suit with GetFunc and LookupFunc.
public abstract class MyClass
{
  protected abstract string Foo(decimal d, object o, int i);
}
//tests
public void MyClassTest()
{
  var proxy = ProxyManager.CreateProxy<MyClass>();
  var fooConfig = ProxyManager.LookupMethod(proxy, "Foo", typeof(decimal), typeof(object), null, typeof(string));
  //...
}

GetProp<>

Returns a configuration for a property (which must be virtual). There are two GetProp methods, one for getters and the other for setters. In order to identify a property without risking invoking before you really mean to, a delegate must be passed to GetProp which does the work of actually invoking the property. As long as the property is virtual, precautions are taken to stop the property body (real or fake) from actually being invoked by using a try-catch pattern. This might be more information than you wanted, but some people have been curious about the motive for the slightly unique syntax of GetProp. Consider the following example:
public abstract class MyClass
{
  public abstract int Prop { get; set; }
}
//tests
public void MyClassTest()
{
  var proxy = ProxyManager.CreateProxy<MyClass>();

  var getConfig = ProxyManager.GetProp<int>(proxy, () => proxy.Prop);
  var setConfig = ProxyManager.GetProp<int>(proxy, v => proxy.Prop = v);
  //...
}
Easy enough when the properties are public. When they are not public, note that there is no LookupProp. But properties are really just methods, and therefore the Lookup* variants will work just the same. Simply prefix getters with get_ and setters with set_. Consider:
public abstract class MyClass
{
  protected abstract int Prop { get; set; }
}
//tests
public void MyClassTest()
{
  var proxy = ProxyManager.CreateProxy<MyClass>();

  var getConfig = ProxyManager.LookupFunc<int>(proxy, "get_Prop");
  var setConfig = ProxyManager.LookupAction<int>(proxy, "set_Prop");
  //...
}
Note that getters are Func<T> and setters are Action<T>. That should be obvious.

GetEvent

Includes GetEventAction and GetEventFunc variants which use the same template structure for strong typed event access as LookupAction and LookupFunc. They return an EventAccess to allow invoking an event outside of the class. Fun for testing. C# limits the syntax options we have with accessing events (they are even more restrictive than properties). Therefore, these methods are more like LookupAction and LookupFunc than they are like GetAction and GetFunc. The proxy object is passed, as well as the event name. Consider the following example:
public abstract class MyClass
{
  public abstract event Func<int> OnInt;
  protected event Action OnAction;
  private event Func<string, int> OnStringInt;
}
//tests
public void MyClassTest()
{
  var proxy = ProxyManager.CreateProxy<MyClass>();
  var eaOnInt = ProxyManager.GetEventFunc<int>(proxy, "OnInt");
  var eaOnAction = ProxyManager.GetEventAction(proxy, "OnActin");
  var eaOnStringInt = ProxyManager.GetEventFunc<string, int>(proxy, "OnStringInt");
  //...
}
Note from this example that events can be configured whether or not they are virtual (this is the one exception). And again to clarify, the only manner in which events can be identified is by string name. If the signature is not known, or complex (e.g. it uses ref or out), LookupEvent can be used (and like GetMethodConfig, LookupEvent works for all types of events, not just complex ones).
public delegate void FooType(ref int i);
public abstract class MyClass
{
  private event FooType Foo;
}
//tests
public void MyClassTest()
{
  var proxy = ProxyManager.CreateProxy<MyClass>();
  var eaFoo = ProxyManager.LookupEvent(proxy, "Foo");
  //...
}

Last edited May 6, 2010 at 4:53 PM by payonel, version 17

Comments

No comments yet.