Initializing Lookup

前端 未结 6 1559
轮回少年
轮回少年 2021-01-07 17:47

How do i declare a new lookup class for a property in the object initializer routine in c#?

E.g.

new Component() { ID = 1, Name = \"MOBO\", Category          


        
相关标签:
6条回答
  • 2021-01-07 18:08

    Per MSDN documentation, there is no public constructor for the Lookup class: http://msdn.microsoft.com/en-us/library/bb460184.aspx

    You can create an instance of a Lookup<TKey, TElement> by calling ToLookup on an object that implements IEnumerable<T>.

    You will want to do something like:

    new Component { ID = 1, Name = "MOBO", Category = new[] { … }.ToLookup(…) }
    

    Update to address comments:

    I'm not sure where you are getting your category info from, so I will make something up…

    new Component {
        ID = 1, 
        Name = "MOBO", 
        Category = new Dictionary<int, string> { 
            { 3, "Beverages" }
            { 5, "Produce" }
        }.ToLookup(o => o.Key, o => o.Value)
    }
    

    My guess is that your categories will come from some other source instead of instantiating a dictionary like I did here.

    0 讨论(0)
  • 2021-01-07 18:10

    Here's my attempt on this. Make sure the key is immutable (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; }
      }
    }
    
    0 讨论(0)
  • 2021-01-07 18:12

    Lookups work with the same concept as Dictionaries, the difference is that Dictionaries map a key to a single value, whereas a Lookup map a key to many values.

    This also means that:

    ILookup<string, Category>
    

    could be seen as:

    IDictionary<string, IEnumerable<Category>>
    

    You basically would want to use ILookup when you want to map many objects/values to a same key. You can build an ILookup from any list of objects, where you want to group these objects by some property. See:

    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;
        }
    }
    

    You could also get all the products for a category like this:

    IEnumerable<Product> eletronics = lookup["Electronics"];
    IEnumerable<Product> fruits = lookup["Fruits"];
    
    0 讨论(0)
  • 2021-01-07 18:14

    From MSDN:

    There is no public constructor to create a new instance of a Lookup<TKey, TElement>.
    Additionally, Lookup<TKey, TElement> objects are immutable, that is, you cannot add or remove elements or keys from a Lookup<TKey, TElement> object after it has been created.

    0 讨论(0)
  • 2021-01-07 18:23

    You can't just use ToLookup; you have to tell it how to find the keys and values:

    // 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)
    }  
    

    I don't understand why you want to use a Lookup here instead of a dictionary, though.

    0 讨论(0)
  • 2021-01-07 18:25

    If you just need to return an empty ILookup for some reason you can return one from an empty dictionary. For example, to make an ILookup<string, int>, you can use this:

    return new Dictionary<string, int>().ToLookup(kvp => kvp.Key, kvp => kvp.Value);
    

    Unfortunately this is the most concise way I can see to do it without having to make a class that implements ILookup yourself.

    0 讨论(0)
提交回复
热议问题