首页 > 解决方案 > 为运行时已知的属性调用通用方法

问题描述

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;
    }

标签: c#asp.net-mvcentity-frameworkgenericsreflection

解决方案


看起来您正在尝试将 an 转换ICollectionIList,这可能会或可能不会起作用。运行时属性的值可能是ICollection未实现的IList

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

public virtual ICollection<ReturnDetail> ReturnDetails { get; set; }

由于您正在检查属性类型是否可以从 分配IEnumerable,所以让我们保持一致并在任何地方使用它。

另一个混淆是它TraverseThroughClass接受一个entity参数,但在上面的语句中你this用来调用属性。你的意思是调用属性entity吗?那会更有意义。否则它正在切换 - 方法的一部分正在调用 的属性,entity而一部分正在调用 on 的属性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);

...并且遍历将遍历 in 中的字符InvoiceNoReturnDetails.


推荐阅读