PropertyInfo属性链末尾的属性

时间:2015-08-29 08:30:57

标签: c# reflection

我有这样的事情:

 ALTER TABLE `emp`.`item` 
ADD INDEX `location_idx` (`categoryId` ASC);
ALTER TABLE `emp`.`item` 
ADD CONSTRAINT `location`
  FOREIGN KEY (`categoryId`)
  REFERENCES `emp`.`location` (`id`)
  ON DELETE NO ACTION
  ON UPDATE NO ACTION;

我也有一个字符串值: class OriginalClass { public Type2 object2 { get; set; } } class Type2 { public Type3 object3 { get; set; } } class Type3 { public Type4 object4 { get; set; } } var obj = new OriginalClass(); var object4 = obj.object2.object3.object4;

这是从"object2.object3.object4"T类型到object4object2的路径(这两个属性都返回对象)。 object3object4上的属性。

如何动态地为最后一个属性object3创建一个PropertyInfo对象?

2 个答案:

答案 0 :(得分:0)

您可以实现类似以下的扩展方法:

public static class TypeExtensions
{
    /// <summary>Looks for a property using an object path where each
    /// property to match is accessed using dot syntax</summary>
    public static PropertyInfo GetPropertyByPath(this Type someType, string objectPath, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public)
    {
        string[] objectPathParts = objectPath.Split('.');

        // #1 property in the object path should be obtained from T
        PropertyInfo currentProperty = someType.GetProperty(objectPathParts[0], bindingFlags);
        for (int propertyIndex = 1; propertyIndex < objectPathParts.Length; propertyIndex++)
        {
            // While all other association properties should be obtained
            // accessing PropertyInfo.PropertyType
            currentProperty = currentProperty.PropertyType.GetProperty(objectPathParts[propertyIndex], bindingFlags);
            if (currentProperty == null)
                throw new ArgumentException("Some property in the object path doesn't exist", "objectPath");
        }

        return currentProperty;
    }
}

以后使用如下:

PropertyInfo object4Info = typeof(OriginalClass).GetPropertyByPath("object2.object3.object4");

方法#2:使用表达式树。更好更简单!

您还可以使用较少的反射来解决问题:

public static class ReflectionHelper
{
    public static PropertyInfo GetPropertyByPath<T>(Expression<Func<T, object>> pathExpr)
    {
        // It must be a member access expression like "x.y.z"
        MemberExpression propertyAccessExpr = pathExpr.Body as MemberExpression;

        // if it's not a member access expression, return null
        if(propertyAccessExpr == null)
            return null;

        return propertyAccessExpr.Member as PropertyInfo;
    }
}

然后在路径中获取最后一个属性信息,如下所示:

PropertyInfo object4Info = ReflectionHelper
     .GetPropertyByPath<OriginalClass>(c => c.object2.object3.object4);

答案 1 :(得分:0)

使用下面的代码,您可以执行以下操作:

PropertyInfo pi = GetPropertyInfoFromPath(obj.GetType(), "object2.object3.object4");

我仍然需要将此作为一个金块发布,但这里是我的反射库的摘录。

public static PropertyInfo GetPropertyInfoFromPath<T>(string path)
{
  var type = typeof(T);
  return GetPropertyInfoFromPath(type, path);
}

public static PropertyInfo GetPropertyInfoFromPath(Type type, string path)
{
  var parts = path.Split('.');
  var count = parts.Count();

  if (count == 0)
    throw new InvalidOperationException("Not a valid path");

  if (count == 1)
    return GetPropertyInformation(type, parts.First());
  else
  {
     var t = GetPropertyInformation(type, parts[0]).PropertyType;
     return GetPropertyInfoFromPath(t, string.Join(".", parts.Skip(1)));
  }
}

如果您确实想要使用表达式(如果可能,则更好,因为它是重构安全的)

public static Type GetPropertyType<T>(Expression<Func<T, object>> expression)
    {
        var info = GetPropertyInformation(expression) as PropertyInfo;
        return info.PropertyType;
    }

    public static MemberInfo GetPropertyInformation<T>(Expression<Func<T, object>> propertyExpression)
    {
        return PropertyInformation(propertyExpression.Body);
    }

    public static PropertyInfo PropertyInformation(Expression propertyExpression)
    {
        MemberExpression memberExpr = propertyExpression as MemberExpression;
        if (memberExpr == null)
        {
            UnaryExpression unaryExpr = propertyExpression as UnaryExpression;
            if (unaryExpr != null && unaryExpr.NodeType == ExpressionType.Convert)
            {
                memberExpr = unaryExpr.Operand as MemberExpression;
            }
        }

        if (memberExpr != null)
        {
            var propertyMember = memberExpr.Member as PropertyInfo;
            if (propertyMember != null)
                return propertyMember;
        }

        return null;
    }

测试。

[Fact]
public void GetPropertyInfo_FromInstanceNestedPropertyUsingPathString_ReturnsPropertyInfo()
{
        var deepType = Helper.GetPropertyInfoFromPath<TestModel>("Nested.Deep");
        var deepDeclaringType = Helper.GetPropertyInfoFromPath<TestModel>("Nested");

        Assert.Equal(typeof(string), deepType.PropertyType);
        Assert.Equal(typeof(NestedModel), deepDeclaringType.PropertyType);
}

类。

public class TestModel : Base
{
    public int Id { get; set; }

    [PickMe]
    public string MyString { get; set; }

    public NestedModel Nested { get; set; }
    public DateTime ClosedAt { get; set; }
}

public class NestedModel
{
    public string Deep { get; set; }
}