我只是在寻找
的替代品if (enumerable.Any())
{
// Code to Map to new type.
}
我知道linq中的foreach方法会这样做,但它会返回void,我需要一些可以将集合传递给新类型的东西。
我试图避免的问题是两次枚举集合并减少圈复杂度。
我想知道linq库中是否存在允许这样的现有方法。
答案 0 :(得分:0)
您可以将ConvertAll与转换器方法一起使用,将您的对象映射到新类型。
https://msdn.microsoft.com/en-us/library/73fe8cwf(v=vs.110).aspx
从MSDN开始
using System;
using System.Drawing;
using System.Collections.Generic;
public class Example
{
public static void Main()
{
List<PointF> lpf = new List<PointF>();
lpf.Add(new PointF(27.8F, 32.62F));
lpf.Add(new PointF(99.3F, 147.273F));
lpf.Add(new PointF(7.5F, 1412.2F));
Console.WriteLine();
foreach( PointF p in lpf )
{
Console.WriteLine(p);
}
List<Point> lp = lpf.ConvertAll(
new Converter<PointF, Point>(PointFToPoint));
Console.WriteLine();
foreach( Point p in lp )
{
Console.WriteLine(p);
}
}
public static Point PointFToPoint(PointF pf)
{
return new Point(((int) pf.X), ((int) pf.Y));
}
}
/* This code example produces the following output:
{X=27.8, Y=32.62}
{X=99.3, Y=147.273}
{X=7.5, Y=1412.2}
{X=27,Y=32}
{X=99,Y=147}
{X=7,Y=1412}
*/
答案 1 :(得分:0)
前段时间我遇到了类似的问题......然后我创建了这个:
// Simple IEnumerable<T> that "uses" an IEnumerator<T> that has
// already received a MoveNext(). "eats" the first MoveNext()
// received, then continues normally. For shortness, both IEnumerable<T>
// and IEnumerator<T> are implemented by the same class. Note that if a
// second call to GetEnumerator() is done, the "real" IEnumerator<T> will
// be returned, not this proxy implementation.
public class EnumerableFromStartedEnumerator<T> : IEnumerable<T>, IEnumerator<T>
{
public readonly IEnumerator<T> Enumerator;
public readonly IEnumerable<T> Enumerable;
// Received by creator. Return value of MoveNext() done by caller
protected bool FirstMoveNextSuccessful { get; set; }
// The Enumerator can be "used" only once, then a new enumerator
// can be requested by Enumerable.GetEnumerator()
// (default = false)
protected bool Used { get; set; }
// The first MoveNext() has been already done (default = false)
protected bool DoneMoveNext { get; set; }
public EnumerableFromStartedEnumerator(IEnumerator<T> enumerator, bool firstMoveNextSuccessful, IEnumerable<T> enumerable)
{
Enumerator = enumerator;
FirstMoveNextSuccessful = firstMoveNextSuccessful;
Enumerable = enumerable;
}
public IEnumerator<T> GetEnumerator()
{
if (Used)
{
return Enumerable.GetEnumerator();
}
Used = true;
return this;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public T Current
{
get
{
// There are various school of though on what should
// happens if called before the first MoveNext() or
// after a MoveNext() returns false. We follow the
// "return default(TInner)" school of thought for the
// before first MoveNext() and the "whatever the
// Enumerator wants" for the after a MoveNext() returns
// false
if (!DoneMoveNext)
{
return default(T);
}
return Enumerator.Current;
}
}
public void Dispose()
{
Enumerator.Dispose();
}
object IEnumerator.Current
{
get
{
return Current;
}
}
public bool MoveNext()
{
if (!DoneMoveNext)
{
DoneMoveNext = true;
return FirstMoveNextSuccessful;
}
return Enumerator.MoveNext();
}
public void Reset()
{
// This will 99% throw :-) Not our problem.
Enumerator.Reset();
// So it is improbable we will arrive here
DoneMoveNext = true;
}
}
和这个
public static class EnumerableExtensions
{
public static bool Any<TSource>(this IEnumerable<TSource> source, out IEnumerable<TSource> newSource)
{
var coll = source as ICollection<TSource>;
if (coll != null)
{
newSource = source;
return coll.Count != 0;
}
var coll2 = source as ICollection;
if (coll2 != null)
{
newSource = source;
return coll2.Count != 0;
}
var enu = source.GetEnumerator();
bool success = enu.MoveNext();
newSource = new EnumerableFromStartedEnumerator<TSource>(enu, success, source);
return success;
}
}
你这样使用:
var enu = new int[] { 1, 2, 3, 4, 5 }.Where(x => x > 3);
IEnumerable<int> enu2;
Console.WriteLine(enu.Any(out enu2));
foreach (var num in enu2)
{
Console.WriteLine(num);
}
基本思想是您开始枚举IEnumerable<>
并仅枚举第一个元素。现在你有一个部分消耗IEnumerator<T>
。然后你&#34;打包&#34;这部分消耗IEnumerator<T>
新IEnumerable<T>
&#34;正确&#34;已构建(示例的enu2
)...当下次使用此IEnumerable<T>
时,它将返回部分消耗的IEnumerator<T>
,并使用一些技巧使其看起来不是&#39真的消耗了。
答案 2 :(得分:0)
Select
似乎是最好的选择,但是如果您的映射很复杂和/或没有生成简单类型,那么您必须循环遍历if
正文中的集合。在这种情况下,您可以手动处理枚举:
var e = enumerable.GetEnumerator();
if (e.MoveNext()) {
// Code to Map to new type.
do {
// map e.Current to new type
} while (e.MoveNext());
}