为运行时已知的属性调用通用方法

时间:2019-03-11 10:28:01

标签: c# asp.net-mvc entity-framework generics reflection

public partial class ReturnHeader
{
        public int ReturnHeaderId { get; set; }
        public int CustomerId { get; set; }
        public string InvoiceNo { get; set; }
        public virtual Customer Customer { get; set; }
        public virtual ICollection<ReturnDetail> ReturnDetails { get; set; }
}

public void TraverseThroughClass<T> (T entity) where T : class
{
 try
 {
  var type = typeof(T);
  PropertyInfo[] props = type.GetProperties();
  foreach (PropertyInfo prop in props)
  {
   if (typeof(IEnumerable).IsAssignableFrom(prop.PropertyType))
  {
  

此检查确定属性是否为列表。

     

问题1:如果为true,则将其投射到列表或任何集合中。   我想做的是,如果属性是一个将其强制转换为集合的集合,并且对于已强制转换的集合调用TraverseThroughClass

    /* Error casting into any collection*/
    //var propertiesValues = prop.GetValue(entity) as IList;
    var listType = GetCollectionItemType(prop.PropertyType);
    foreach (var listItem in propertiesValues)
    {
  

问题2:对于集合中的每个项目,请调用TraverseThroughClass(T实体)

    }
  }
  else
  {
   Console.WriteLine("Prop Name : " + prop.Name + " Prop Value : " 
            + prop.GetValue(entity, null));
  }
}
 }
 catch (Exception e)
 {
  throw;
 }
}     

 public static Type GetCollectionItemType(Type collectionType)
 {
  var types = collectionType.GetInterfaces()
            .Where(x => x.IsGenericType
                && x.GetGenericTypeDefinition() == typeof(IEnumerable<>))
            .ToArray();
        return types.Length == 1 ? types[0].GetGenericArguments()[0] : null;
    }

1 个答案:

答案 0 :(得分:1)

您似乎正在尝试将ICollection强制转换为IList,但这可能有效也可能无效。运行时属性的值可能是未实现ICollection的{​​{1}}。

如果此属性的运行时值实现IList,它将起作用,但如果失败,则它将失败。

IList

由于您要检查属性类型是否可以从public virtual ICollection<ReturnDetail> ReturnDetails { get; set; } 进行分配,因此我们保持一致,并在各处使用它。

另一个困惑是IEnumerable使用一个TraverseThroughClass参数,但是在上面的语句中,您正在使用entity来调用该属性。您是否要在this上调用属性?那会更有意义。否则,它会切换-方法的一部分正在调用entity的属性,而一部分正在调用entity上的属性,this是在其中调用该方法的类实例。

为解决这个问题,我将TraverseThroughClass移到其自己的静态类中,并对entity参数执行所有操作。我还删除了GetCollectionItemType。它被调用了,但是调用的结果从未使用过,因此看起来好像我们不需要它。

这是您方法的修改版本,移到了自己的类中。 (请注意,我并没有解决此问题的大局,只是试图解决问题中的问题。)

public static class Traversal
{
    public static void TraverseThroughClass<T>(T entity) where T : class
    {
        var type = typeof(T);
        PropertyInfo[] props = type.GetProperties();
        foreach (PropertyInfo prop in props)
        {
            if (typeof(IEnumerable).IsAssignableFrom(prop.PropertyType))
            {
                var propertiesValues = prop.GetValue(entity);

                // What if the property value is null?
                if (propertiesValues == null) continue;
                var collection = propertiesValues as IEnumerable;
                foreach (var listItem in collection)
                {
                    // I don't know what you want to do with these. 
                    // I'm just confirming that we're able to inspect them.
                    Debug.WriteLine("Success, we're iterating over the items!!"); 
                }
            }
            else
            {
                Debug.WriteLine("Prop Name : " + prop.Name + " Prop Value : "
                                  + prop.GetValue(entity, null));
            }
        }
    }
}

这仍然留下了您的方法将遍历InvoiceNo的细节,因为它实现了IEnumerable(它是字符的集合。)如果您不想这样做,则可以专门排除字符串或更详细地说明您要做的类型。

这时我可以执行以下代码:

var returnHeader = new ReturnHeader
{
    ReturnDetails = new List<ReturnDetail>(
        new ReturnDetail[] { new ReturnDetail(), new ReturnDetail() }),
    InvoiceNo = "Invoice!"
};
Traversal.TraverseThroughClass(returnHeader);

...并且遍历将遍历InvoiceNo中的字符和ReturnDetails中的项目。