在我正在实现的校验和计算算法中,输入必须是偶数个字节-如果不是,则必须在末尾打包一个额外的零字节。
我不想通过实际添加元素来修改输入数据到我的方法(并且输入可能是不可修改的)。我也不想创建新的数据结构并复制输入。
我想知道LINQ是否是创建类似以下内容的轻量级IEnumerable
的好选择:
void Calculate(IList<byte> input)
{
IEnumerable<byte> items = (input.Count & 1 ==0) ? items : X(input,0x0);
foreach(var i in items)
{
...
}
}
即X(...)
会是什么样?
您可以使用此迭代器(yield return
)扩展方法将额外的项目添加到IEnumerable<T>
的末尾,而无需首先对元素进行迭代(您需要按顺序进行操作才能获得.Count
值)。
请注意,应检查input
是IReadOnlyCollection<T>
还是IList<T>
,因为这意味着可以提前知道.Count
时可以使用更优化的代码路径。
public static IEnumerable<T> EnsureModuloItems<T>( this IEnumerable<T> source, Int32 modulo, T defaultValue = default )
{
if( source is null ) throw new ArgumentNullException(nameof(source));
if( modulo < 1 ) throw new ArgumentOutOfRangeException( nameof(modulo), modulo, message: "Value must be 1 or greater." );
//
Int32 count = 0;
foreach( T item in source )
{
yield return item;
count++;
}
Int32 remainder = count % modulo;
for( Int32 i = 0; i < remainder; i++ )
{
yield return defaultValue;
}
}
使用方式如下:
foreach( Byte b in input.EnsureModuloItems( modulo: 2, defaultValue: 0x00 ) )
{
}
您可能会为此使用Concat
方法>>
Concat
我还对您的代码进行了一些更改,
IEnumerable<byte> items = input.Count() % 2 == 0 ? input : input.Concat(new[] { (byte)0x0 });
没有Count
属性,您应该使用IEnumerable<T>
方法。
由于Count()
接受Concat()
,因此需要IEnumerable<T>
ao数组。您可以创建一个简单的扩展方法,将单个项目包装为List<T>
IEnumerable<T>
并使用它
internal static class Ext
{
public static IEnumerable<T> Yield<T>(this T item)
{
yield return item;
}
}