C# 用于将多个具有非空值的属性收集到集合中的简明C代码?

C# 用于将多个具有非空值的属性收集到集合中的简明C代码?,c#,collections,properties,nullable,C#,Collections,Properties,Nullable,这是一个改变的基本问题。给定这样一个类: public class X { public T A; public T B; public T C; ... // (other fields, properties, and methods are not of interest here) } 我正在寻找一种简洁的方法来编写一个将返回所有a、B、C。。。在可枚举集合中不为null的。假设将这些字段声明为数组不是一个选项 public IEnumerab

这是一个改变的基本问题。给定这样一个类:

public class X
{
    public T A;
    public T B;
    public T C;
    ...

    // (other fields, properties, and methods are not of interest here)
}
我正在寻找一种简洁的方法来编写一个将返回所有a、B、C。。。在可枚举集合中不为null的。假设将这些字段声明为数组不是一个选项

public IEnumerable<T> GetAllNonNullABCs(this X x)
{
    // ?
}
或者:

IEnumerable<T> AllABCs(this X x)
{
    yield return x.A;
    yield return x.B;
    yield return x.C;
    ...
    yield break;
}
2仅返回非空值:

您可以使用关键字创建直接返回元素的可枚举项,而不是填充列表:

public IEnumerable<T> GetAllNonNullAs(this X x)
{
    if (x.A != null) yield return x.A;
    if (x.B != null) yield return x.B;
    if (x.C != null) yield return x.C;
    ...
}
要消除空检查,可以编写一个返回所有值的方法,并过滤结果:

public IEnumerable<T> GetAllAs(this X x)
{
    yield return x.A;
    yield return x.B;
    yield return x.C;
    ...
}

public IEnumerable<T> GetAllNonNullAs(this X x)
{
    return x.GetAllAs().Where(y => y != null);
}
林克去营救

public IEnumerable<T> GetAllNonNullAs(this X x)
{
    return from pi in x.GetType().GetProperties()
           let val = pi.GetValue(x, null)
           where val != null
           select (T) val;
}

您可能还想添加一个检查,以确保该值的类型为T,但我不确定这是否是您的问题。

您可以使用迭代器块来执行此操作,尽管它的详细程度不会低很多

public IEnumerable<T> GetAllNonNullAs(this X x)
{
    if(x.A != null) yield return x.A;
    if(x.B != null) yield return x.B;
    if(x.C != null) yield return x.C;
}

在定义类时,可能应该使用数组或其他集合类型:

public class X
{
    public T[] ABC = new T[3];
    ...
}
然后它就变得微不足道了:

return ABC.Where(x => x != null);

我建议将其他一些答案混合起来。使用yield返回属性,然后使用.Where LINQ扩展方法过滤掉空值。

这在很大程度上牺牲了性能,不必指定每个属性。是的,但是。。。在A、B、C之后,意味着不止三个属性。这将适用于任意数量的属性。此外,这将循环所有属性。如果你有一些特定的方法不应该是其中的一部分,那么你就注定要失败了。。。在可枚举集合中不为null的-这正是此方法所做的。对性能没有要求,只对特定子集没有要求。为什么要为15个属性编写15行代码,而4行就足够了?实际上,可能还有其他字段/属性不应该包括在内;这就是为什么我把其他字段、属性。。。不感兴趣的代码位。非常好的结合产量和。在哪里LINQ查询!这就是我一直在寻找的代码改进!正如我所说,这不是一个选择。我只将字段命名为A、B、C,。。。出于演示目的,但在我的真实类中,它们会有更多不同的名称,不能也不应该包含在数组中。@stakx:哦,我错过了这一点。但是请注意,即使不能在每次需要时通过从头创建数组来更改类,您仍然可以使用相同的技术。这就是你接受的答案,没错。我最初认为收益率解决方案是最好的,但在看到基于阵列的解决方案有多么简单之后,我改变了主意。我接受了,因为你的答案非常简短明了。也许对于大量的属性来说,由于内存占用较小,涉及产量的解决方案更可取。
public static IEnumerable<T> GetAllNonNullAs(this X x)
{
    return new[] { x.A, x.B, x.C }.Where(t => t != null);
}
public class X
{
    public T[] ABC = new T[3];
    ...
}
return ABC.Where(x => x != null);
public static IEnumerable<T> GetAllNonNullAs(this X x)
{
    return new[] { x.A, x.B, x.C }.Where(t => t != null);
}
public IEnumerable<T> GetAllNonNullAs(this X x)
{
    return this.Add(X.A, X.B, X.C);
}

private List<T> Add(params X[] items)
{
   var result = new List<T>();
   foreach(var item in items)
   {
       if(item != null)
       {
           result.Add(item);
       }
   }
}