在C#中,当尝试设置一个私有类型的私有数组的元素时,事情会变得复杂。想象一下这个假设的类来测试:
public static class MyClass
{
private static readonly MyInnerClass[] myArray = new MyInnerClass[10];
public static bool IsEmpty()
{
foreach (var item in myArray)
{
if ((item != null) && (!string.IsNullOrEmpty(item.Field)))
{
return false;
}
}
return true;
}
private class MyInnerClass
{
public string Field;
}
}
如果想写一个测试用例,当数组有“非空”条目时,需要先设置数组。使用Visual Studio生成的访问器,会这样写:
[TestClass()]
public class MyClassTest
{
[TestMethod()]
public void IsEmpty_NotEmpty_ReturnsFalse()
{
for (int i = 0; i < 10; i++)
{
MyClass_Accessor.myArray[i] = new MyClass_Accessor.MyInnerClass { Field = i.ToString() };
}
bool expected = false;
bool actual;
actual = MyClass.IsEmpty();
Assert.AreEqual(expected, actual);
}
}
但是测试会失败,因为虽然可以作为MyClass_Accessor.MyInnerClass实例读取私有数组myArray的元素,但不能这样写入。要做到这一点,测试应该这样写:
[TestClass()]
public class MyClassTest
{
[TestMethod()]
public void IsEmpty_NotEmpty_ReturnsFalse()
{
for (int i = 0; i < 10; i++)
{
MyClass_Accessor.ShadowedType.SetStaticArrayElement(
"myArray",
new MyClass_Accessor.MyInnerClass { Field = i.ToString() }.Target, i);
}
bool expected = false;
bool actual;
actual = MyClass.IsEmpty();
Assert.AreEqual(expected, actual);
}
}
但是,这样就失去了访问器的所有强类型,因为需要写出数组字段的名称。由于字段的访问器是一个属性,可以编写一组扩展方法,为获取字段名称。类似这样:
public static class PrivateTypeExtensions
{
public static void SetStaticArrayElement(
this PrivateType self, Expression> expression,
T value, params int[] indices)
{
object elementValue = (value is BaseShadow) ?
(value as BaseShadow).Target : value;
self.SetStaticArrayElement(
((PropertyInfo)((MemberExpression)(expression.Body)).Member).Name,
elementValue, indices);
}
public static void SetStaticArrayElement(
this PrivateType self, Expression> expression, BindingFlags invokeAttr, T value,
params int[] indices)
{
object elementValue = (value is BaseShadow) ?
(value as BaseShadow).Target : value;
self.SetStaticArrayElement(
((PropertyInfo)((MemberExpression)(expression.Body)).Member).Name,
invokeAttr, elementValue, indices);
}
}
[TestClass()]
public class MyClassTest
{
[TestMethod()]
public void IsEmpty_NotEmpty_ReturnsFalse()
{
for (int i = 0; i < 10; i++)
{
MyClass_Accessor.ShadowedType.SetStaticArrayElement(() =>
MyClass_Accessor.myArray,
new MyClass_Accessor.MyInnerClass { Field = i.ToString() }, i);
}
bool expected = false;
bool actual;
actual = MyClass.IsEmpty();
Assert.AreEqual(expected, actual);
}
}