C# 从接受动态参数作为输入的lambda获取属性名

C# 从接受动态参数作为输入的lambda获取属性名,c#,.net,dynamic,lambda,C#,.net,Dynamic,Lambda,我正在设计一个测试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); 我想编写TestP

我正在设计一个测试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);
}
private void AssertPropertyIsNotNull(动态结果,Func propertySelector)
{
var propertyPath=GetPropertyPathFromFunc(propertySelector);
var errorMessage=$“{propertyPath}未正确填充。”
IsNotNull(propertySelector(结果),errorMessage);
}
在本例中,我需要
GetPropertyPathFromFunc
的主体


问题如何编写一个方法,以类似
o=>City.Name的lambda作为输入,并返回类似
“City.Name”的字符串
结果。

当您使用
动态
时,您会松开类型安全和编译时成员名称检查,因此使用字符串作为属性名称没有任何区别

这里有一个解决方案。它需要大量的错误检查和异常处理。您还可以添加缓存机制以减少反射开销

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");
公共静态bool IsPropertyNull(动态对象,字符串propertyName)
{
var path=propertyName.Split('.');
对象tempObject=obj;
for(int i=0;ix.Name==path[i]);
tempObject=property.GetValue(tempObject);
}
返回tempObject==null;
}
bool isTitleNull=IsPropertyNull(结果,“标题”);
bool iscitynameull=IsPropertyNull(结果为“City.Name”);

如前所述,不幸的是,
动态
不能在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;
    }
}
私有静态字符串GetPropertyPathFromFunc(Func propertySelector)
{
var collector=新的PropertyNameCollector();
属性选择器(收集器);
返回收集器名称;
}
私有类PropertyNameCollector:DynamicObject
{
公共字符串名称{get;private set;}
公共重写bool TryGetMember(GetMemberBinder绑定器,输出对象结果)
{
如果(!string.IsNullOrEmpty(名称))
姓名+=”;
名称+=活页夹。名称;
结果=这个;
返回true;
}
}