C# 将LINQ与包装阵列一起使用
我是LINQ的新手,我正在做一个简单的项目来学习这项技术的特性 目前我有一个静态类,它封装了一个对象数组(一种简单的工厂)。假设它看起来如下所示:C# 将LINQ与包装阵列一起使用,c#,arrays,linq,C#,Arrays,Linq,我是LINQ的新手,我正在做一个简单的项目来学习这项技术的特性 目前我有一个静态类,它封装了一个对象数组(一种简单的工厂)。假设它看起来如下所示: public static class Factory { private static Item[] items = new Item[] { // items are created here }; // ... } 现在我可以在工厂中添加一些函数来查询内部数组,例如 public st
public static class Factory
{
private static Item[] items = new Item[]
{
// items are created here
};
// ...
}
现在我可以在工厂中添加一些函数来查询内部数组,例如
public static Item GetByID(ItemID id)
{
var query =
from item in items
where item.ID == id
select item;
return query.First();
}
但是,这需要我修改Factory类的内部结构。有没有办法从“外部世界”编写这样的查询
public class OtherClass
{
var result = from it in Factory select ...
}
是的,你可以。只需在“外部世界”的工厂使用linq即可:
public class OtherClass
{
public Item Get(ItemId id)
{
return Factory.Items.SingleOrDefault(i => i.ID == id);
}
}
当然,要做到这一点,您需要将
项
数组的访问修饰符更改为公共
是的,您可以。只需在“外部世界”的工厂使用linq即可:
public class OtherClass
{
public Item Get(ItemId id)
{
return Factory.Items.SingleOrDefault(i => i.ID == id);
}
}
当然,要做到这一点,您需要将项
数组的访问修饰符更改为公共
使用表达式树
public class OtherClass
{
public Item Get(ItemId id)
{
return Factory.Get(i => i.id == id);
}
}
并将get方法更改为
public Item Get(Expression<Func<Item,bool>> filter)
{
return items.SingleOrDefault(filter);
}
公共项获取(表达式筛选器)
{
返回项。SingleOrDefault(过滤器);
}
但是,除非在factory类中封装一些其他逻辑,即仅选择未软删除的行,否则这种方法毫无意义。使用表达式树
public class OtherClass
{
public Item Get(ItemId id)
{
return Factory.Get(i => i.id == id);
}
}
并将get方法更改为
public Item Get(Expression<Func<Item,bool>> filter)
{
return items.SingleOrDefault(filter);
}
公共项获取(表达式筛选器)
{
返回项。SingleOrDefault(过滤器);
}
但是,除非您在factory类中封装一些其他逻辑,即仅选择未软删除的行,否则这种方法没有什么意义。有很多选项 最简单的方法是公开一个公共属性,该属性允许您想要允许的内容:
public static class Factory
{
private static Item[] items = new Item[]
{
// items are created here
};
public static IEnumerable<IReadableItem> Items{ get { return items; } }
// ...
}
如果您真的想变得更花哨,您甚至可以实现自己的LINQ提供程序。从语言的角度来看,LINQ表达式语法只映射到特定的方法名,因此如果您有一个实现了
.Where()
和.Select()
方法的类,那么您可以按照自己的意愿实现它,人们在尝试做你的方法不支持的事情之前不会知道有什么不同。有很多选择
最简单的方法是公开一个公共属性,该属性允许您想要允许的内容:
public static class Factory
{
private static Item[] items = new Item[]
{
// items are created here
};
public static IEnumerable<IReadableItem> Items{ get { return items; } }
// ...
}
如果您真的想变得更花哨,您甚至可以实现自己的LINQ提供程序。从语言的角度来看,LINQ表达式语法只映射到特定的方法名,因此如果您有一个实现了
.Where()
和.Select()
方法的类,那么您可以按照自己的意愿实现它,人们在尝试做一些您的方法不支持的事情之前不会知道有什么不同。一种可能性是为非静态类实现IQueryable
:
public class Factory<T> : IQueryable<T>
{
protected T[] _items = new T[]{};
public Type ElementType
{
// or typeof(T)
get { return _items.AsQueryable().ElementType; }
}
public System.Linq.Expressions.Expression Expression
{
get { return _items.AsQueryable().Expression; }
}
public IQueryProvider Provider
{
get { return _items.AsQueryable().Provider; }
}
public IEnumerator<T> GetEnumerator()
{
return ( IEnumerator<T> )_items.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _items.GetEnumerator();
}
}
用法:
var specificItem = Factories.ItemFactory
.Where( item => item.ID == id )
.SingleOrDefault();
一种可能性是为非静态类实现
IQueryable
:
public class Factory<T> : IQueryable<T>
{
protected T[] _items = new T[]{};
public Type ElementType
{
// or typeof(T)
get { return _items.AsQueryable().ElementType; }
}
public System.Linq.Expressions.Expression Expression
{
get { return _items.AsQueryable().Expression; }
}
public IQueryProvider Provider
{
get { return _items.AsQueryable().Provider; }
}
public IEnumerator<T> GetEnumerator()
{
return ( IEnumerator<T> )_items.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _items.GetEnumerator();
}
}
用法:
var specificItem = Factories.ItemFactory
.Where( item => item.ID == id )
.SingleOrDefault();
如果它是公共财产,您可以访问它
Factory.WhicheverCollection.Where(item=>item.id==whicheverid)
有什么问题吗?我的意思是使用内部数组而不公开它。类似于添加[]运算符,允许用户将对象用作容器。如果可以对类进行迭代,则可以这样做。这样做的方法是使类实现IEnumerable
。从内存来看,Linq做了一些奇怪的事情,可以使用GetIterator或其他工具处理任何事情,但您可能不应该相信这一点。明白了-您认为哪种方法更好?将内部集合公开的方法,或者为您的财产实现IEnumerable?一个公共的get
和一个私有的set
的方法,我肯定会这样做。接口在相当大的程度上声明了意图。如果你想让人们把工厂
看作一个列表,那么IEnumerable
是一个不错的选择。在我看来,任何名为Factory
的东西都不应该是列表,因为没有人会想到这一点。如果它是公共财产,你可以访问它Factory.WhicheverCollection.Where(item=>item.id==whicheverid)
有什么问题吗?我的意思是使用内部数组而不公开它。类似于添加[]运算符,允许用户将对象用作容器。如果可以对类进行迭代,则可以这样做。这样做的方法是使类实现IEnumerable
。从内存来看,Linq做了一些奇怪的事情,可以使用GetIterator或其他工具处理任何事情,但您可能不应该相信这一点。明白了-您认为哪种方法更好?将内部集合公开的方法,或者为您的财产实现IEnumerable?一个公共的get
和一个私有的set
的方法,我肯定会这样做。接口在相当大的程度上声明了意图。如果你想让人们把工厂
看作一个列表,那么IEnumerable
是一个不错的选择。在我看来,任何名为Factory
的东西都不应该是列表,因为没有人会想到这一点。这就是问题所在-这可以在不公开内部集合的情况下完成,而是使用包装类吗?您必须向工厂添加一个Get方法,该方法是公共的,它返回数组项
,“外部世界”可以使用linq对其进行操作。认识到这只是语义上的不同,但却完成了相同的事情;他可以让类实现IEnumerable
。这对于OP试图完成的任务来说是不必要的复杂。我同意。只有在你说他“必须”按你的方式做的时候,我才不同意。我会按你的方式来做。这就是问题所在-这可以在不公开内部集合的情况下完成,而是使用包装类吗?你必须向工厂添加一个Get方法,该方法是公共的,它返回数组项
,其中