C# 类是否可以从集合继承并仍然有效地与LINQ交互?
我有一个从集合继承的C#类。我大量使用LINQ,因此对我的类方法的调用与LINQ调用混合在一起。不幸的是,这意味着我经常将LINQ返回的I枚举返回到管道中间的类类型。这会导致代码过多,并且计算效率低下 另一个解决方案是将类方法实现为扩展方法。这更有效,但在这种情况下,我将不得不重新生成可以从集合继承的功能 有没有一种方法可以从集合继承,但仍然有效地与LINQ交互 下面的程序包含两个查询。第一个查询从派生类调用一个方法,但它还需要对ToMyList()进行O(n)调用。第二个查询效率更高,但它没有使用派生类C# 类是否可以从集合继承并仍然有效地与LINQ交互?,c#,.net,linq,C#,.net,Linq,我有一个从集合继承的C#类。我大量使用LINQ,因此对我的类方法的调用与LINQ调用混合在一起。不幸的是,这意味着我经常将LINQ返回的I枚举返回到管道中间的类类型。这会导致代码过多,并且计算效率低下 另一个解决方案是将类方法实现为扩展方法。这更有效,但在这种情况下,我将不得不重新生成可以从集合继承的功能 有没有一种方法可以从集合继承,但仍然有效地与LINQ交互 下面的程序包含两个查询。第一个查询从派生类调用一个方法,但它还需要对ToMyList()进行O(n)调用。第二个查询效率更高,但它没有
using System.Collections.Generic;
using System.Linq;
namespace StackOverflow
{
// A custom list that can multiply every element by a constant integer.
public class MyList : List<int>
{
public MyList() : base() { }
public MyList(IEnumerable<int> items) : base(items) { }
public MyList Multiply(int n)
{
for(int i = 0; i < Count; ++i)
this[i] *= n;
return this;
}
}
public static class Extensions
{
// Convert from IEnumerable<int> to MyList.
public static MyList ToMyList(this IEnumerable<int> items)
{
return new MyList(items);
}
// An extension version of the multipy method.
public static IEnumerable<int> Multiply(this IEnumerable<int> items, int n)
{
foreach (var item in items)
yield return n * item;
}
}
class Program
{
static void Main(string[] args)
{
// Create a large list.
var myList = new MyList();
for (int i = 0; i < 1000000; ++i) myList.Add(i);
// Call the MyList.Multiply method.
var query1 = myList.Skip(100).ToMyList().Multiply(5);
// Call the extension version of the Multiply method.
var query2 = myList.Skip(100).Multiply(5);
}
}
}
使用System.Collections.Generic;
使用System.Linq;
命名空间堆栈溢出
{
//可以将每个元素乘以一个常量整数的自定义列表。
公共类MyList:列表
{
公共MyList():base(){}
公共MyList(IEnumerable项):基本(项){}
公共MyList乘法(整数n)
{
对于(int i=0;i简单的答案是否定的。一方面,列表(以及任何衍生工具)必须管理自己的数据副本。另一方面,Linq转换数据而不存储数据。因此,如果您执行Linq操作,并且希望它返回到MyList实例中,那么您必须承担存储它的O(N)成本
根据您的预期用途,您可以做的是修改MyList,以便它不从list派生,而是保存一个可枚举项,并在该可枚举项上存储转换。这将允许:
public class MyNonList : IEnumerable<int>
{
IEnumerable<int> _inner;
public MyNonList(IEnumerable<int> inner)
{
_inner = inner;
}
public MyNonList Multiply(int n)
{
return new MyNonList(_inner.Select(i => i * n));
}
public IEnumerator<int> GetEnumerator() => _inner.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)_inner).GetEnumerator();
}
public static class Extensions
{
// Convert from IEnumerable<int> to MyList.
public static MyNonList ToMyNonList(this IEnumerable<int> items)
{
return new MyNonList(items);
}
}
class Program
{
static void Main(string[] args)
{
// Create a large list.
var list = new List<int>();
for (int i = 0; i < 1000000; ++i)
list.Add(i);
var myList = new MyNonList(list);
// Call the MyList.Multiply method.
MyNonList myList2 = myList.Skip(100).ToMyNonList().Multiply(5);
}
}
公共类MyNonList:IEnumerable
{
IEnumerable\u-inner;
公共MyNonList(IEnumerable内部)
{
_内部=内部;
}
公共MyNonList乘法(整数n)
{
返回新的MyNonList(_inner.Select(i=>i*n));
}
公共IEnumerator GetEnumerator()=>\u inner.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()=>((IEnumerable)u inner.GetEnumerator();
}
公共静态类扩展
{
//从IEnumerable转换为MyList。
公共静态MyNonList ToMyNonList(此IEnumerable items)
{
返回新的MyNonList(项目);
}
}
班级计划
{
静态void Main(字符串[]参数)
{
//创建一个大列表。
var list=新列表();
对于(int i=0;i<1000000;++i)
列表.添加(i);
var myList=新的MyNonList(列表);
//调用MyList.Multiply方法。
MyNonList myList2=myList.Skip(100).ToMyNonList().Multiply(5);
}
}
但是在这个简单的例子中,除了实现静态扩展方法之外,这真的提供了很少的东西。(顺便说一句,这是一件非常合理的事情)
您还可以将MyList拆分为两个独立的类:一个派生自List并实际保存数据的类;第二种方式包含了感兴趣的转换方法,完成它自己的ToMyList实现,最终实现并存储可枚举数据。您是否考虑过创建自己的枚举器和Linq扩展方法,以便它可以处理MyList类型。如果您创建一个全新的MyList对象,它就不是真正的“强制转换”,是的,它的效率非常低。为什么需要非扩展方法乘法
?另外,在单个链式方法调用中混合使用使对象发生变异的代码和不包含该对象的代码会使以后查看该方法的其他人感到困惑。您确定这是低效的吗?如果将支持随机访问的集合(ICollection
)传递到列表中,它将使用ICollection.CopyTo()
,我知道在任何情况下,它都使用快速的Array.Copy()
调用。为什么你首先要继承一个收藏@除了明显的分配问题之外,如果链中的下一个调用是.First()
,该怎么办?将LINQ延迟执行与强制枚举和对象分配混合起来似乎不是一个好主意。对其他使用它的人来说,这不会是“最不惊讶的”。