我正在设计一个测试API。我希望有一个像这样的API:
// There is a dynamic object which should be tested to have certain properties.
dynamic result = SomeMethod();
AssertPropertyIsNotNull(resut, o => o.Title);
AssertPropertyIsNotNull(resut, o => o.City.Name);
我想写TestProperty
方法来断言属性并显示正确的消息它失败的方式如下:
private void AssertPropertyIsNotNull(dynamic result, Func<dynamic, object> propertySelector)
{
var propertyPath = GetPropertyPathFromFunc(propertySelector);
var errorMessage = $"{propertyPath} is not filled properly."
Assert.IsNotNull(propertySelector(result), errorMessage);
}
在此示例中,我需要GetPropertyPathFromFunc
的正文。
问题如何编写一个方法,将o => City.Name
之类的lambda作为输入,并返回类似"City.Name"
的字符串作为结果。
答案 0 :(得分:2)
当您使用dynamic
时,您会失去类型安全性并编译时间成员名称检查,因此将字符串用作属性名称没有任何区别。
这是一个解决方案。它需要广泛的错误检查和异常处理。您还可以添加缓存机制以减少反射开销。
public static bool IsPropertyNull(dynamic obj, string propertyName)
{
var path = propertyName.Split('.');
object tempObject = obj;
for (int i = 0; i < path.Length; i++)
{
PropertyInfo[] dynamicProperties = tempObject.GetType().GetProperties();
var property = dynamicProperties.Single(x => x.Name == path[i]);
tempObject = property.GetValue(tempObject);
}
return tempObject == null;
}
bool isTitleNull = IsPropertyNull(result, "Title");
bool isCityNameNull = IsPropertyNull(result, "City.Name");
答案 1 :(得分:1)
如上所述,遗憾的是dynamic
无法在C#编译器当前实现的表达式树中使用。作为替代方法,您可以使用自定义动态对象调用委托,该对象收集所访问的属性名称。我在下面演示了这一点。请注意,这仅适用于您给出的有限语法,并且我没有花费太多精力来处理更复杂的事情。
private static string GetPropertyPathFromFunc(Func<dynamic, object> propertySelector)
{
var collector = new PropertyNameCollector();
propertySelector(collector);
return collector.Name;
}
private class PropertyNameCollector : DynamicObject
{
public string Name { get; private set; }
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (!string.IsNullOrEmpty(Name))
Name += ".";
Name += binder.Name;
result = this;
return true;
}
}