假设我写了一个类,代码如下
namespace XXXXXXX
{
public class A
{
private int Add(int a, int b)
{
return a + b;
}
}
}
如果要单元测试A的Add 方法的话, 由于Add 是private 的, 单元测试代码无法直接访问,这时候,我们可以利用反射来作. 微软很多的bug也多数通过反射,访问private 属性或者字段可以fix
VS 2005 自动生成的单元测试代码
[DeploymentItem("XXXXXXX.exe")]
[TestMethod()]
public void AddTest()
{
A target = new A();
TestProject1.XXXXXXX_AAccessor accessor = new TestProject1.XXXXXXX_AAccessor(target);
int a = 0; // TODO: Initialize to an appropriate value
int b = 0; // TODO: Initialize to an appropriate value
int expected = 0;
int actual;
actual = accessor.Add(a, b);
Assert.AreEqual(expected, actual, "XXXXXXX.A.Add did not return the expected value.");
Assert.Inconclusive("Verify the correctness of this test method.");
}
[TestMethod()]
public void AddTest()
{
A target = new A();
TestProject1.XXXXXXX_AAccessor accessor = new TestProject1.XXXXXXX_AAccessor(target);
int a = 0; // TODO: Initialize to an appropriate value
int b = 0; // TODO: Initialize to an appropriate value
int expected = 0;
int actual;
actual = accessor.Add(a, b);
Assert.AreEqual(expected, actual, "XXXXXXX.A.Add did not return the expected value.");
Assert.Inconclusive("Verify the correctness of this test method.");
}
而这里的XXXXXXX_AAccessor就是一个wrapper 来通过反射调用对象的方法,代码如下
[System.Diagnostics.DebuggerStepThrough()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TestTools.UnitTestGeneration", "1.0.0.0")]
internal class XXXXXXX_AAccessor : BaseAccessor {
protected static Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType m_privateType = new Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType(typeof(global::XXXXXXX.A));
internal XXXXXXX_AAccessor(global::XXXXXXX.A target) :
base(target, m_privateType) {
}
internal int Add(int a, int b) {
object[] args = new object[] {
a,
b};
int ret = ((int)(m_privateObject.Invoke("Add", new System.Type[] {
typeof(int),
typeof(int)}, args)));
return ret;
}
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TestTools.UnitTestGeneration", "1.0.0.0")]
internal class XXXXXXX_AAccessor : BaseAccessor {
protected static Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType m_privateType = new Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType(typeof(global::XXXXXXX.A));
internal XXXXXXX_AAccessor(global::XXXXXXX.A target) :
base(target, m_privateType) {
}
internal int Add(int a, int b) {
object[] args = new object[] {
a,
b};
int ret = ((int)(m_privateObject.Invoke("Add", new System.Type[] {
typeof(int),
typeof(int)}, args)));
return ret;
}
}
这时候,有些人可能又疑惑,为啥private 的东西最终还是可以调用,起到封装的目的了吗?
.....................
问题2: private 的到底是什么意思,我特意浏览了一下C#语言规范.
一个成员的可访问域由(可能是不连续的)程序文本节组成,从那里可以访问该成员。出于定义成员可访问域的目的,如果成员不是在某个类型内声明的,就称该成员是顶级的;如果成员是在其他类型内声明的,就称该成员是嵌套的。此外,程序的程序文本定义为包含在该程序的所有源文件中的全部程序文本,而类型的程序文本定义为包含在该类型(可能还包括嵌套在该类型内的类型)的“类体”、“结构体”、“接口体”或“枚举体”中的开始和结束(“{”和“}”)标记之间的全部程序文本。
· 如果 M 的已声明可访问性为 private,则 M 的可访问域是 T 的程序文本。
class A
{
int x;
static void F(B b) {
b.x = 1; // Ok,这里x事实上是private 的变量
}
}
class B: A
{
static void F(B b) {
b.x = 1; // Error, x not accessible
}
}
{
int x;
static void F(B b) {
b.x = 1; // Ok,这里x事实上是private 的变量
}
}
class B: A
{
static void F(B b) {
b.x = 1; // Error, x not accessible
}
}
那反射呢? 反射可以不遵守嘛?呵呵,一会儿给出个完整的解释.