[DRAFT] Ease API Designing with .NET Interception Technology
There will be another series of articles discussing solving real problem (during our R&D process) with .NET's interception technology (specifically, RealProxy/TransparentProxy for intercepting method invocation for mocking API implementation).
With technology discussed in this installation, you will be assisted a lot during API designing phases, eliminating thousands lines of codes in effect to achieve the same runtime behavior (not counting performance) and that allowing you to incrementally implement your library.
Phase O: Initiative/Goals
1. get bored writing tedious fields, property getters n' setters, etc?
class X
{
private int _a;
public int A
{
get { return _a; }
set { if (_a != value) _a = value; }
}
}
Sure we could define interfaces, like this:
interface X
{
int A { get; set; }
}
But without at least one concrete implementation, this code just cannot run and use.
2. Getting bored writing trival constructors merely to initialize various properties/fields?
class X
{
public X() { _a = 0; }
public X(int a) { _a = a; }
}
3. In an AJAX world, everything's changing incrementally. how to track object's changes and deal with only changed parts?
X x = new X();
DetectChanges(x); // -> nothing
x.A = 123;
DetectChanges(x); // -> x.A changed to 123
CommitChanges(x);
DetectChanges(x); // -> nothing
x.A = 123;
DetectChanges(x); // -> nothing!
x.A = 1234;
DetectChanges(x); // -> x.A changed to 1234
4. And to serialize such changes as XML/JSON, XmlSerializer is just no-use in such situation.
X x = new X(); // we want: <X />
x.A = 123; // we want: <X a="123" /> or X {a:123;}
x.B = 456; // we want: <X a="123" b="456" /> or X {a:123; b:456;}
Phase I: A Mock Factory
1. Simple Type Implementation
interface M
{
int A { get; set; }
}
void Test()
{
M m = MockFactory.Create<M>();
Debug.Assert(m!=null);
m.A = 123;
Debug.Assert(m.A==123);
}
2. Nested Type
interface N
{
M B { get; set; }
}
void Test()
{
N n = MockFactory.Create<N>();
Debug.Assert(n!=null);
M b = n.B;
Debug.Assert(b!=null);
}
3. Improvement and Refactor
a) Get unassigned ValueType/ReferenceType?
b) DefaultValue?
Q. Constraint while set value? CannotBeNull(), Within(min, max), etc.
4. Implement of GetType(), ToString(), GetHashCode() and Equals()
5. Delegate inner method to external extension concrete class?
interface X
{
void F();
}
class ExtensionX: X
{
void F() { Debug.Assert(true); }
}
void Test()
{
X x = MockFactory.Create<X>();
x.F(); // -> NotImplementedException
MockFactory.RegisterExtenstionClass<X, ExtensionX>();
x.F(); // -> Okay now
}
6. Refactor General-4 method to ExtensionBase:
class ExtensionBase
{
Type GetType() {}
string ToString() {}
int GetHashCode() {}
bool Equals() {}
}
How an extension instance could get "context" information about target instance?
Phase II: A Mocked Factory
1. Getting bored with MockFactory.Create<T>()? Let's define our own factory interface!
interface Factory
{
M CreateM();
}
void Test()
{
Factory factory = MockedFactory.Create<Factory>();
Debug.Assert(factory!=null);
M m = factory.CreateM();
Debug.Assert(m!=null);
}
2. How about non-default constructor?
interface Factory
{
M CreateM(int A);
}
void Test()
{
Factory factory = MockedFactory.Create<Factory>();
Debug.Assert(factory!=null);
M m = factory.CreateM(123);
Debug.Assert(m!=null);
Debug.Assert(m.A==123);
}
Main challenge here is to locate property member for setting value when there is multiple interface inheritance. For instance,
interface X
{
int A { get; set; }
}
interface Y: X
{
int B { get; set; }
}
From typeof(Y) you can only get a member information (more specifically, PropertyInfo) for name "B" but not "A", because "A" is declared in interface X. So, you need to find a property info from a combination of Y and its interfaces implemented, in this case, X.
Q.
interface M
{
int A { get; set; }
int B { get; set; }
}
interface Factory
{
M CreateM(int A);
M CreateM(int B); // <-- conflict with CreateM(int A)
M CreateM(int A, int B);
}
Phase III: Solve a Real Problem
1. Get changeset during object operation:
interface M
{
int A { get; set; }
}
interface Factory
{
M CreateM();
M CreateM(int A);
}
void Test()
{
Factory factory = MockedFactory.Create<Factory>();
M m;
// create "clean" instance
m = factory.CreateM();
PropertyInfo PropA = m.GetType().GetProperty("A");
PropertyInfo PropN = m.GetType().GetProperty("N");
Debug.Assert(ChangeDetector.HasChanged<M>(PropA)==false);
m.A = 123;
Debug.Assert(ChangeDetector.HasChanged<M>(PropA)==true);
// create instance with
m = factory.CreateM(123);
Debug.Assert(ChangeDetector.HasChanged<M>(PropA)==true);
}
posted on 2006-10-29 20:44:00 by jgtm2000 评论(0) 阅读(830)