如何在c#?
中的对象初始化程序例程中为属性声明一个新的查找类E.g。
new Component() { ID = 1, Name = "MOBO", Category = new Lookup<int, string> }
类别位总是会出现编译错误。
我有一个名为Category
的属性,类型为Lookup<int, string>
,我希望通过
new Component() { ID = 1, Name = "MOBO", Category = new Lookup<int, string> };
但我无法克服编译错误。
答案 0 :(得分:22)
根据MSDN文档,Lookup
类没有公共构造函数:http://msdn.microsoft.com/en-us/library/bb460184.aspx
您可以通过在实现Lookup<TKey, TElement>
的对象上调用ToLookup
来创建IEnumerable<T>
的实例。
您需要执行以下操作:
new Component { ID = 1, Name = "MOBO", Category = new[] { … }.ToLookup(…) }
更新以发表评论:
我不确定你从哪里获得类别信息,所以我会做点什么......
new Component {
ID = 1,
Name = "MOBO",
Category = new Dictionary<int, string> {
{ 3, "Beverages" }
{ 5, "Produce" }
}.ToLookup(o => o.Key, o => o.Value)
}
我的猜测是你的类别将来自其他一些来源,而不是像我在这里那样实例化字典。
答案 1 :(得分:8)
来自MSDN:
没有公共构造函数来创建Lookup<TKey, TElement>
的新实例
此外,Lookup<TKey, TElement>
对象是不可变的,也就是说,在创建Lookup<TKey, TElement>
对象后,您无法添加或删除元素或键。
答案 2 :(得分:3)
这是我对此的尝试。确保密钥是不可变的(Gist)。
public class MultiValueDictionary<TKey, TElement>
: Collection<TElement>, ILookup<TKey, TElement>
{
public MultiValueDictionary(Func<TElement, TKey> keyForItem)
: base(new Collection(keyForItem))
{
}
new Collection Items => (Collection)base.Items;
public IEnumerable<TElement> this[TKey key] => Items[key];
public bool Contains(TKey key) => Items.Contains(key);
IEnumerator<IGrouping<TKey, TElement>>
IEnumerable<IGrouping<TKey, TElement>>.GetEnumerator() => Items.GetEnumerator();
class Collection
: KeyedCollection<TKey, Grouping>, IEnumerable<TElement>, IList<TElement>
{
Func<TElement, TKey> KeyForItem { get; }
public Collection(Func<TElement, TKey> keyForItem) => KeyForItem = keyForItem;
protected override TKey GetKeyForItem(Grouping item) => item.Key;
public void Add(TElement item)
{
var key = KeyForItem(item);
if (Dictionary != null && Dictionary.TryGetValue(key, out var collection))
collection.Add(item);
else
Add(new Grouping(key) { item });
}
public bool Remove(TElement item)
{
var key = KeyForItem(item);
if (Dictionary != null && Dictionary.TryGetValue(key, out var collection)
&& collection.Remove(item))
{
if (collection.Count == 0)
Remove(key);
return true;
}
return false;
}
IEnumerator<TElement> IEnumerable<TElement>.GetEnumerator()
{
foreach (var group in base.Items)
foreach (var item in group)
yield return item;
}
const string IndexError = "Indexing not supported.";
public int IndexOf(TElement item) => throw new NotSupportedException(IndexError);
public void Insert(int index, TElement item) => Add(item);
public bool Contains(TElement item) => Items.Contains(item);
public void CopyTo(TElement[] array, int arrayIndex) =>
throw new NotSupportedException(IndexError);
new IEnumerable<TElement> Items => this;
public bool IsReadOnly => false;
TElement IList<TElement>.this[int index]
{
get => throw new NotSupportedException(IndexError);
set => throw new NotSupportedException(IndexError);
}
}
class Grouping : Collection<TElement>, IGrouping<TKey, TElement>
{
public Grouping(TKey key) => Key = key;
public TKey Key { get; }
}
}
答案 3 :(得分:1)
你不能只使用ToLookup;你必须告诉它如何找到键和值:
// from ChaosPandion's code
using System.Linq; // make sure you have the using statement
var component = new Component()
{
ID = 1,
Name = "MOBO",
Category = (Lookup<int, string>)
(new Dictionary<int, string>() { {1, "one"} })
.ToLookup(p=>p.Key, p=>p.Value)
}
我不明白你为什么要在这里使用Lookup而不是字典。
答案 4 :(得分:0)
查找与“字典”具有相同的概念,不同之处在于“字典”将键映射到单个值,而“查找”将键映射到多个值。 / p>
这也意味着:
ILookup<string, Category>
可以被视为:
IDictionary<string, IEnumerable<Category>>
要将多个对象/值映射到同一键时,您基本上希望使用ILookup
。您可以从任何对象列表中构建一个ILookup
,并在其中按某种属性对这些对象进行分组。参见:
public class Product
{
public string Name { get; set; }
public string Category { get; set; }
public decimal Price { get; set; }
}
var products = new List<Product>();
products.Add(new Product { Name = "TV", Price = 400, Category = "Electronics" });
products.Add(new Product { Name = "Computer", Price = 900, Category = "Electronics" });
products.Add(new Product { Name = "Keyboard", Price = 50, Category = "Electronics" });
products.Add(new Product { Name = "Orange", Price = 2, Category = "Fruits" });
products.Add(new Product { Name = "Grape", Price = 3, Category = "Fruits" });
// group by category
ILookup<string, Product> lookup = products.ToLookup(prod => prod.Category);
foreach (var item in lookup)
{
// this first loop would run two times
// because there are two categories: Electronics and Fruits
string category = item.Key;
decimal totalPriceForCategory = item.Sum(i => i.Price);
foreach (var product in item)
{
// for the electronics, this would loop three times
// for the fruits, this would loop two times
string name = product.Name;
decimal price = product.Price;
}
}
您还可以获取以下类别的所有产品:
IEnumerable<Product> eletronics = lookup["Electronics"];
IEnumerable<Product> fruits = lookup["Fruits"];
答案 5 :(得分:0)
如果由于某种原因只需要返回一个空的ILookup
,则可以从一个空的字典中返回一个。例如,要制作ILookup<string, int>
,可以使用以下代码:
return new Dictionary<string, int>().ToLookup(kvp => kvp.Key, kvp => kvp.Value);
不幸的是,这是我看到的最简洁的方法,而不必创建自己实现ILookup
的类。