我正在尝试基于xml数据动态创建一个模拟。这对于大多数类型都可以正常工作,但枚举却有些棘手。 ???在我的代码中期望枚举的类型。但是显然类型在编译时是未知的,因此我不得不求助于反射。我可能必须使用MakeGenericMethod来直接或间接调用Expression.Lambda,但这似乎只是将问题转移为模拟。安装程序也需要编译时类型。那就是我被困住的地方。任何帮助表示赞赏。
public static Mock<T> DeserializeMock<T>(XElement node)
where T : class
{
var mock = new Mock<T>();
foreach (var property in PropertyInfoHelper.EnumeratePublicAndInternalProperties(typeof(T)))
{
var attribute = node.Attribute(property.Name);
if (property.PropertyType == typeof(string))
{
var parameter = Expression.Parameter(typeof(T));
var body = Expression.PropertyOrField(parameter, property.Name);
var propertyExpression = Expression.Lambda<Func<T, string>>(body, parameter);
mock.Setup(propertyExpression).Returns(attribute.Value);
}
// ... other types omitted for brevity...
else if (property.PropertyType.IsEnum)
{
var parameter = Expression.Parameter(typeof(T));
var body = Expression.PropertyOrField(parameter, property.Name);
var propertyExpression = Expression.Lambda<Func<T, ???>>(body, parameter);
mock.Setup(propertyExpression).Returns(convertToEnum(attribute.Value, property.PropertyType));
}
}
return mock;
}
答案 0 :(得分:0)
您最终将不得不使用反射来获取设置的类型
//...omitted for brevity...
else if (property.PropertyType.IsEnum) {
var parameter = Expression.Parameter(typeof(T));
var body = Expression.PropertyOrField(parameter, property.Name);
var delegateType = typeof(Func<,>).MakeGenericType(typeof(T), property.PropertyType);
var propertyExpression = Expression.Lambda(delegateType, body, parameter);
var value = convertToEnum(attribute.Value, property.PropertyType);
var setup = mock.GetType().GetMethods()
.FirstOrDefault(m => m.Name == "Setup" && m.ContainsGenericParameters)
.MakeGenericMethod(property.PropertyType);
var result = setup.Invoke(mock, new object[] { propertyExpression });
var returns = result.GetType().GetMethod("Returns", new[] { property.PropertyType });
returns?.Invoke(result, new object[] { value });
}
//...omitted for brevity...
我还根据原始代码假设,在模拟中设置的所有成员都是虚拟成员或抽象成员。
概念证明
[TestClass]
public class MyTestClass {
[TestMethod]
public void MyTestMethod() {
//Arrange
XElement element = new XElement("root",
new XAttribute("MyProperty1", "Hello World"),
new XAttribute("MyEnumProperty", "Value2")
);
//Act
var mock = DeserializeMock<MyClass>(element);
//Assert
var actual = mock.Object;
actual.MyEnumProperty.Should().Be(MyEnum.Value2);
actual.MyProperty1.Should().Be("Hello World");
}
public class MyClass {
public virtual string MyProperty1 { get; set; }
public virtual MyEnum MyEnumProperty { get; set; }
}
public enum MyEnum {
Value1,
Value2
}
//...
}