如何使嵌套的foreach循环方法通用



我想获得所有(唯一(Apple(或Oranges(对象的列表:

var theBigFruitsList = new List<Fruits>{
new Fruits(){
Apples = new List<Apple>{
new Apple { Id = 1 },
new Apple { Id = 2 }
}
},
Oranges = new List<Orange>{
new Orange { Id = 4 },
new Orange { Id = 5 }
}
},
FruitBoolean = False,
FruitCount = 4,
},
new Fruits(){
Apples = new List<Apple>{
new Apple { Id = 3 },
new Apple { Id = 1 },
}
},
Oranges = new List<Orange>{
new Orange { Id = 6 },
}
}
FruitBoolean = False,
FruitCount = 3,
}
}

我为它写了这样的方法:

public static List<Apple> GetApplesFromBigFruitsList(List<Fruits> theBigFruitsList )
{
var dc = new Dictionary<long, Apple>();
foreach (var fruits in theBigFruitsList)
{
foreach (var apple in fruits.Apples)
{
if (!dc.ContainsKey(apple.Id))
dc.Add(apple.Id, apple);
}
}
return dc.Values.ToList();
}

但是,除了苹果和橙子之外,这个物体中还有许多其他类型的"水果",我有超过10次这样的方法,其中苹果一词被橙色取代。。将其通用化是有意义的。

我写了这个函数,但它给出了一个错误,因为Fruits类没有实现枚举器。请帮忙!

public static List<T> FilterFruits<T>(T typeToGet, List<Fruits> theBigFruitsList)
{
List<T> fruitResult = new List<T>();
var fruitType = typeToGet.GetType();
foreach (var fruits in theBigFruitsList)
{
foreach (var fruit in fruits) //errors, intention is to loop over all properties in the Fruits entity to find one specific type
if (fruit.GetType() == fruitType) //check if type is Apple
{
fruitResult.AddRange(fruits); //add the Apples to a list
}
}
return fruitResult;
}

类别:

public class Fruits{
public List<Apple> Apples { get; set; }
public List<Orange> Oranges { get; set; }
public List<Pineapple> Pineapples { get; set; }
public List<Mango> Mangos { get; set; }
public bool FruitBoolean { get; set; }
public long FruitCount { get; set; }
}
public class Apple{
public long Id { get; set; }
}
public class Orange{
public long Id { get; set; }
}   
public class Pineapple{
public long Id { get; set; }
}   
public class Mango{
public long Id { get; set; }
}   

所需的方法结果:

var Apples = List<Apple>{
new Apple { Id = 1 },
new Apple { Id = 2 },
new Apple { Id = 3 }
}

有一个大列表

把每种水果都放在单独的清单里……很奇怪。我建议你把它们放在一个清单里。如果你不能改变设计,你可以在运行时将它们组合起来,如下所示:

IEnumerable<object> GetAllFruits(Fruits bigFruitlist)
{
return ((IEnumerable<object>)bigFruitlist.Apples) 
.Concat((IEnumerable<object>)bigFruitlist.Oranges) 
.Concat((IEnumerable<object>)bigFruitlist.Mangoes) 
.Concat((IEnumerable<object>)bigFruitlist.Pineapples); 
}

当然,如果所有的水果都有一个通用接口会更好——那么你就不需要IEnumerable<object>了——但如果你也不能做出改变,这仍然可以工作。

一旦你有了组合列表,剩下的就很容易了:

List<T> FilterFruits<T>(Fruits bigFruitlist)
{
return GetAllFruits(bigFruitList).OfType<T>().ToList();
}

使用列表数组

如果出于某种原因,您希望避免枚举所有列表(即列表庞大,性能是一个问题(,您也可以使用列表数组来执行此操作。

object[] GetAllFruitLists(Fruits bigFruitlist)
{
return new object[]
{
bigFruitlist.Apples,
bigFruitlist.Oranges,
bigFruitlist.Mangoes, 
bigFruitlist.Pineapples
}; 
}
List<T> FilterFruits<T>(Fruits bigFruitlist)
{
return GetAllFruitLists(bigFruitList).OfType<List<T>>().Single();
}

要在运行时查询对象的类型,请使用反射。像这样:

public static List<T> FilterFruits<T>(List<Fruits> fruitsList) where T : IFruit
{
List<T> fruitResult = new List<T>();
var fruitType = typeof(T);
foreach (var fruits in fruitsList)
{
foreach (var fp in typeof(Fruits).GetProperties())
{
if (fp.PropertyType == typeof(List<T>)) //check if type is Apple
{
fruitResult.AddRange((List<T>)(object)fp.GetValue(fruits)); //add the Apples to a list
}
}
}
return fruitResult;
} 

(T)(object)o是C#的惯用语,用于执行编译器无法验证的转换,并且可能在运行时失败,我们知道它不会,但编译器不能,因为它不理解反射。

要在没有反射的情况下做到这一点(对于某些场景来说可能太慢(,您可以做这样的事情:

public static List<T> GetDistinct<T>( IEnumerable<Fruits> fruitsList) where T : IFruit
{
var ft = typeof(T);
Func<Fruits, List<T>> picker;
if (ft == typeof(Apple))
{
picker = (fruits) => (List<T>)(object)fruits.Apples;
}
else if (ft == typeof(Mango))
{
picker = (fruits) => (List<T>)(object)fruits.Mangos;
}
else
{
throw new NotImplementedException($"Fruit Type {ft.Name} not supported");
}
var rv = new Dictionary<long, T>();
foreach (var t in fruitsList.SelectMany(picker))
{
if (!rv.ContainsKey(t.Id))
{
rv.Add(t.Id, t);
}
}
return rv.Values.ToList();

}

最新更新