【问题标题】:How to call Count on a bunch of ISet<T> properties where T varies如何在 T 变化的一堆 ISet<T> 属性上调用 Count
【发布时间】:2019-07-24 14:39:30
【问题描述】:

我有一个类有一堆ISet&lt;T&gt; 类型的属性,其中 T 因属性而异。

我想遍历一个对象的属性,找到某种 ISet 的属性,然后对每个属性调用 Count。

谢谢。

【问题讨论】:

  • 到目前为止你尝试了什么..?
  • @MongZhu,我想我可以检查类 names 的子字符串“ISet”,但是 ISet 不是 ISet,所以我不认为我可以使用 isisAssignableFrom
  • 是要调用集合上的Count属性,还是只想获取集合中的项目数?
  • @Sean,我需要 Count 属性,但我很好奇如果我只需要项目数,你会提出什么建议...

标签: c# .net generics system.reflection


【解决方案1】:

这可能有效,obj 是一个目标对象:

Type targetType = obj.GetType();
foreach (var propertyInfo in targetType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy))
{
    var isetInterface = propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(ISet<>)
        ? propertyInfo.PropertyType
        : null;

    if(isetInterface == null)
    {
        isetInterface = propertyInfo.PropertyType
            .GetInterfaces()
            .FirstOrDefault(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(ISet<>));
    }

    if (isetInterface != null)
    {
        object isetPropertyValue = propertyInfo.GetValue(obj);

        var countPropertyInfo = isetInterface
            .GetInterfaces()
            .First(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(ICollection<>))
            .GetProperty("Count");

        if (isetPropertyValue == null)
        {
            Console.WriteLine($".{propertyInfo.Name} == null");
        }
        else
        {
            var count = countPropertyInfo.GetValue(isetPropertyValue);
            Console.WriteLine($".{propertyInfo.Name}.Count == {count}");
        }
    }
}

【讨论】:

  • 如果属性类似于HashSet&lt;double&gt;,它可以工作,但如果属性已经是接口ISet&lt;double&gt;,则它不起作用。您检查了所有接口,但没有检查属性本身。例如:它不会处理这个类:public class Foo { public ISet&lt;double&gt; bar {get; set;} }
【解决方案2】:

@Renat 的回答对我有用,但我将其调整为我觉得更方便的东西:

        public virtual string counts => typeof(Changeset)
        .GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy)
        .Where(prop => prop.GetValue(this) != null && count(prop) > 0)
        .Select(prop => $@".{prop.Name}.Count == {count(prop)}")
        .Join("\n");

    private int count(PropertyInfo prop)
    {
        var name = prop.Name;
        var isetInterface = prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(ISet<>)
            ? prop.PropertyType
            : null;

        if (isetInterface == null)
        {
            isetInterface = prop.PropertyType
                .GetInterfaces()
                .FirstOrDefault(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(ISet<>));
        }

        if (isetInterface != null)
        {
            object isetPropertyValue = prop.GetValue(this);

            var countPropertyInfo = isetInterface
                .GetInterfaces()
                .First(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(ICollection<>))
                .GetProperty("Count");

            if (isetPropertyValue == null)
                return 0;
            else
                return (int) countPropertyInfo.GetValue(isetPropertyValue);
        }

        return 0;
    }

另外,我发现如果我可以按名称引用属性,我可以使用

    private string count<T>(Func<Changeset, ISet<T>> selector)
    {
        var count = selector(this).Count;
        return count > 0 ? $"\n{typeof(T).Name}s:\t\t{count}" : "";
    }

$"{count(x => x.prop)}"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-08
    • 1970-01-01
    • 2021-08-26
    • 1970-01-01
    • 2013-03-06
    • 1970-01-01
    相关资源
    最近更新 更多