IEnumerable<T> 使用 c# 在函数内访问 T 的属性

Posted

技术标签:

【中文标题】IEnumerable<T> 使用 c# 在函数内访问 T 的属性【英文标题】:IEnumerable<T> Access properties of T inside a function using c# 【发布时间】:2021-05-16 06:53:23 【问题描述】:

有一个 c# 函数接受 IEnumerable&lt;T&gt; 的列表。我想在这个函数中写一些 linq 查询,但是T 的属性似乎没有得到。

在编写 Linq 语句之前,我们如何将 T 映射到特定类型?在本例中,它的类型为 CustomerAddress,具有 3 个属性 Id, Name, Gender

private IEnumerable<IEnumerable<T>> SmartSplit<T>(IEnumerable<T> sourceList)

    // not able to access any props of T; in this case T is of type CustomerAddress
    int itemsCount = sourceList.Where(v => v.???==).Count();  

    

我想获取 itemsCount 作为此函数中名称长度 > 50 的项目的计数。 Linq 会反对一个列表就像

int itemsCount = sourceList.Where(p => p.Name.Length > 50).Count();
        

但是如何访问SmartSplit 函数内的属性Name?我可以看到有一种方法可以通过先转换到一个列表然后像下面这样编写 LINQ 来做到这一点

private IEnumerable<IEnumerable<T>> SmartSplit<T>(IEnumerable<T> sourceList)

    List<CustomerAddress> sourceListCopy = sourceList as  List<CustomerAddress>;
    int itemsCount=  sourceListCopy.Where(p => p.Name.Length > 50).Count();

我们可以在不强制转换和复制到函数内的临时列表的情况下做到这一点吗?

【问题讨论】:

那么不要让SmartSplit 接受IEnumerable&lt;T&gt;!让它接受IEnumerable&lt;CustomerAddress&gt; 似乎您的函数使用IEnumerable&lt;CustomerAdress&gt;,而不是IEnumerable&lt;T&gt;,除非T 被限制为CustomerAdress 如果您不想将其限制为CustomerAddress,您可以使用声明string Name 属性的接口,并使CustomerAddress 实现该接口。使用您当前的代码,无法保证任何类型 T 都将具有 Name 属性 附带说明,.Where(p =&gt; ...).Count() 可以重写 .Count(p =&gt; ...) 如果您不想指定类型或接口而不是泛型,那么您也可以将Where 子句作为参数传入。 【参考方案1】:

如果你不仅想传递 CustomerAddress ,你应该提取你的公共属性到接口,然后使用带有“where”子句的约束。 示例:

  public interface ICustomerInfo
    
        string Name  get; set; 
    

    private IEnumerable<IEnumerable<T>> SmartSplit<T>(IEnumerable<T> sourceList) where T: ICustomerInfo, class
    
        int itemsCount = sourceList.Where(v => v.Name.Length > 50).Count();
        return default;
    

【讨论】:

为什么建议使用约束而不是IEnumerable&lt;ICustomerInfo&gt; 所以,在你的情况下,方法总是应该返回接口。如果您不需要,可以通过约束返回确切的类型。例如:IEnumerable&lt;CustomerInfo&gt; split = SmartSplit(new List&lt;CustomerInfo&gt;()); IEnumerable&lt;SuperCustomerInfo&gt; split1 = SmartSplit(new List&lt;SuperCustomerInfo&gt;()); 带接口:IEnumerable&lt;ICustomerInfo&gt; split = SmartSplit(new List&lt;CustomerInfo&gt;()); IEnumerable&lt;ICustomerInfo&gt; split1 = SmartSplit(new List&lt;SuperCustomerInfo&gt;());

以上是关于IEnumerable<T> 使用 c# 在函数内访问 T 的属性的主要内容,如果未能解决你的问题,请参考以下文章

无法从“System.Collections.IList”转换为“System.Collections.Generic.IEnumerable<T>”

将 IEnumerable<Ienumerable<T>> 转换为 Dictionary<key,IEnumerable<T>>

IEnumerable<T> 使用 c# 在函数内访问 T 的属性

List<T>,ArrayList,IEnumerable的区别

如何将两个 IEnumerable<T> 连接成一个新的 IEnumerable<T>?

对参数使用 IReadOnlyCollection<T> 而不是 IEnumerable<T> 以避免可能的多次枚举