How to modify ILookup object in C# 4.0? - collections

Before .NET 3.5 was released, I use
Dictionary<TKey, List<TValue>>
for containing data. But I just found that .NET 3.5 provides new collection type that is ILookup class that can represent my old complex data type.
I always create ILookup object by using LINQ extension method (ToLookup method). But I do not know how to modify ILookup object.
Is it possible? Or I need to create by using union method and call ToLookup method again.
Thanks,

You don't, it's immutable. You have listed both of the reasonable options; either to use a dictionary of sub-collections or to keep creating new lookups.

Here is an example of an implementation of ILookup that can be manipulated. It wraps around a Dictionary of List's of elements. It is completely generic. I couldn't think of a better name. :)
public class LookupDictionary<TKey, TElement> : ILookup<TKey, TElement>
{
private Dictionary<TKey, List<TElement>> _dicLookup = new Dictionary<TKey, List<TElement>>();
public LookupDictionary()
{
}
public LookupDictionary(ILookup<TKey, TElement> a_lookup)
{
foreach (var grouping in a_lookup)
{
foreach (var element in grouping)
AddElement(grouping.Key, element);
}
}
public IEnumerable<TElement> AllElements
{
get
{
return (from key in _dicLookup.Keys
select _dicLookup[key])
.SelectMany(list => list);
}
}
public int Count
{
get
{
return AllElements.Count();
}
}
public IEnumerable<TElement> this[TKey a_key]
{
get
{
List<TElement> list;
if (_dicLookup.TryGetValue(a_key, out list))
return list;
return new TElement[0];
}
}
public bool Contains(TKey a_key)
{
return _dicLookup.ContainsKey(a_key);
}
public void Add(TKey a_key, TElement a_element)
{
AddElement(a_key, a_element);
}
public void RemoveKey(TKey a_key)
{
_dicLookup.Remove(a_key);
}
public IEnumerator<IGrouping<TKey, TElement>> GetEnumerator()
{
return GetGroupings().GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return (GetGroupings() as System.Collections.IEnumerable).GetEnumerator();
}
private void AddElement(TKey a_key, TElement a_element)
{
List<TElement> list;
if (!_dicLookup.TryGetValue(a_key, out list))
{
list = new List<TElement>();
_dicLookup.Add(a_key, list);
}
list.Add(a_element);
}
private IEnumerable<IGrouping<TKey, TElement>> GetGroupings()
{
return from key in _dicLookup.Keys
select new LookupDictionaryGrouping<TKey, TElement>
{
Key = key,
Elements = _dicLookup[key]
} as IGrouping<TKey, TElement>;
}
}
public class LookupDictionaryGrouping<TKey, TElement> : IGrouping<TKey, TElement>
{
public TKey Key
{
get;
set;
}
public IEnumerable<TElement> Elements
{
get;
set;
}
public IEnumerator<TElement> GetEnumerator()
{
return Elements.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return (Elements as System.Collections.IEnumerable).GetEnumerator();
}
}

As mquander mentioned, the lookup is immutable. However, you can build a new lookup with additional or removed values.
// Add a new value
myLookup = myLookup
.SelectMany(l => l.Select(v => new {l.Key, Value = v}))
.Union(new[] {new {Key = myNewKey, Value = myNewValue}})
.ToLookup(a => a.Key, a => a.Value);
// Remove an old value
myLookup = myLookup
.SelectMany(l => l.Select(v => new {l.Key, Value = v}))
.Where(a => a.Value != myOldValue)
.ToLookup(a => a.Key, a => a.Value);

Related

How to get Binding-Context on creating DataTemplate

Is there a way to get the Binding-Context itself in an enumerated template?
this.CollectionView.ItemTemplate = new DataTemplate(() =>
{
var view = new SubView();
view.SetBinding(SubView.SourceProperty, new Binding()
{
Source = ??? // <- here
});
return view;
};
Note:
Path = "." works fine on Android. but on iOS, the source is duplicated.
I have already checked that there are no duplicates in CollectionView.ItemsSource.
I'm new to the platform I hope I can help.
I understand that you want to get the BindingContext of each element in the list. If I am interpreting correctly, then this is what you can do:
public partial class NotificationsPage : ContentPageBase
{
public NotificationsPage()
{
InitializeComponent();
CollectionView.ItemTemplate = new DataTemplate(() =>
{
return new Item();
});
}
}
public class Item : ContentView
{
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
if (BindingContext is ItemModel item)
{
var name = item.Name;
}
}
}
public class ItemModel
{
public string Name { get; set; }
}
DataTemplate does not contain an accessible BindingContext, the BindingContext is passed to the element containing the DataTemplate.

How do I find settable properties with Json.NET using a ContractResolver? [duplicate]

Is there a way to ignore get-only properties using the Json.NET serializer but without using JsonIgnore attributes?
For example, I have a class with these get properties:
public Keys Hotkey { get; set; }
public Keys KeyCode
{
get
{
return Hotkey & Keys.KeyCode;
}
}
public Keys ModifiersKeys
{
get
{
return Hotkey & Keys.Modifiers;
}
}
public bool Control
{
get
{
return (Hotkey & Keys.Control) == Keys.Control;
}
}
public bool Shift
{
get
{
return (Hotkey & Keys.Shift) == Keys.Shift;
}
}
public bool Alt
{
get
{
return (Hotkey & Keys.Alt) == Keys.Alt;
}
}
public Modifiers ModifiersEnum
{
get
{
Modifiers modifiers = Modifiers.None;
if (Alt) modifiers |= Modifiers.Alt;
if (Control) modifiers |= Modifiers.Control;
if (Shift) modifiers |= Modifiers.Shift;
return modifiers;
}
}
public bool IsOnlyModifiers
{
get
{
return KeyCode == Keys.ControlKey || KeyCode == Keys.ShiftKey || KeyCode == Keys.Menu;
}
}
public bool IsValidKey
{
get
{
return KeyCode != Keys.None && !IsOnlyModifiers;
}
}
Do I need to add [JsonIgnore] to all of them (I also have many other classes), or there is better way to ignore all get-only properties?
You can do this by implementing a custom IContractResolver and using that during serialization. If you subclass the DefaultContractResolver, this becomes very easy to do:
class WritablePropertiesOnlyResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);
return props.Where(p => p.Writable).ToList();
}
}
Here is a test program demonstrating how to use it:
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
class Program
{
static void Main(string[] args)
{
Widget w = new Widget { Id = 2, Name = "Joe Schmoe" };
JsonSerializerSettings settings = new JsonSerializerSettings
{
ContractResolver = new WritablePropertiesOnlyResolver()
};
string json = JsonConvert.SerializeObject(w, settings);
Console.WriteLine(json);
}
}
class Widget
{
public int Id { get; set; }
public string Name { get; set; }
public string LowerCaseName
{
get { return (Name != null ? Name.ToLower() : null); }
}
}
Here is the output of the above. Notice that the read-only property LowerCaseName is not included in the output.
{"Id":2,"Name":"Joe Schmoe"}
Use the OptIn mode of JSON.net and you'll only need to decorate the properties you want to serialize. This isn't as good as automatically opting out all read only properties, but it can save you some work.
[JsonObject(MemberSerialization.OptIn)]
public class MyClass
{
[JsonProperty]
public string serializedProp { get; set; }
public string nonSerializedProp { get; set; }
}
Udate: Added another possibility using reflection
If the above solution still isn't quite what you're looking for, you could use reflection to make dictionary objects which would then be serialized. Of course the example below will only work for simple classes, so you would need to add recursion if your classes contain other classes. This should at least point you in the right direction.
The subroutine to put the filtered result into a dictionary:
private Dictionary<String, object> ConvertToDictionary(object classToSerialize)
{
Dictionary<String, object> resultDictionary = new Dictionary<string, object>();
foreach (var propertyInfo in classToSerialize.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (propertyInfo.CanWrite) resultDictionary.Add(propertyInfo.Name, propertyInfo.GetValue(classToSerialize, null));
}
return resultDictionary;
}
A snippet showing its use:
SampleClass sampleClass = new SampleClass();
sampleClass.Hotkey = Keys.A;
var toSerialize = ConvertToDictionary(sampleClass);
String resultText = JsonConvert.SerializeObject(toSerialize);
You can use a contract resolver like this:
public class ExcludeCalculatedResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
property.ShouldSerialize = _ => ShouldSerialize(member);
return property;
}
internal static bool ShouldSerialize(MemberInfo memberInfo)
{
var propertyInfo = memberInfo as PropertyInfo;
if (propertyInfo == null)
{
return false;
}
if (propertyInfo.SetMethod != null)
{
return true;
}
var getMethod = propertyInfo.GetMethod;
return Attribute.GetCustomAttribute(getMethod, typeof(CompilerGeneratedAttribute)) != null;
}
}
It will exclude calculated properties but include C#6 get only properties and all properties with a set method.
Json.net does have the ability to conditionally serialize properties without an attribute or contract resolver. This is especially useful if you don't want your project to have a dependency on Json.net.
As per the Json.net documentation
To conditionally serialize a property, add a method that returns boolean with
the same name as the property and then prefix the method name with
ShouldSerialize. The result of the method determines whether the
property is serialized. If the method returns true then the property
will be serialized, if it returns false then the property will be
skipped.

Dynamically attach entry to context

I am using .Net 4.5 and Entity Framework 6 to create a REST Web API.
In my Update methods I need to attach the object recieved in the web api, back to the dbcontext. I have achieved this using the code below. What I want to do now, is to make this code reusable so that I can call AttachToContext for any object in the model.
I understand that I have to use generic type T and TEntity, but I cannot find any suitable examples.
//Repository.cs
public void UpdateOrderItem(OrderItem orderItem)
{
try
{
AttachToContext(orderItem);
_context.SaveChanges();
}
catch (Exception e)
{
}
}
private void AttachToContext(OrderItem orderItem)
{
var entry = _context.Entry<OrderItem>(orderItem);
if (entry.State == EntityState.Detached)
{
var attachedEntity = FindExistingEntity(orderItem.Id);
if (EntityExists(attachedEntity))
{
UpdateEntityValues(attachedEntity, orderItem);
}
else
{
entry.State = EntityState.Modified;
}
}
}
private OrderItem FindExistingEntity(int id)
{
var set = _context.Set<OrderItem>();
return set.Find(id);
}
private void UpdateEntityValues(OrderItem existing, OrderItem updated)
{
var attachedEntry = _context.Entry(existing);
attachedEntry.CurrentValues.SetValues(updated);
}
private bool EntityExists(object entity)
{
return entity != null;
}
Your AttachToContext has dependency to primary key property, orderItem.Id, to change it into dynamic, you can introduce an interface and implement to all entities you have or just passing the id as parameters.
Interface
public interface IEntity
{
public int Id { get; set; }
}
public class OrderItem : IEntity
{
// body
}
Then modify the AttachToContext as follow.
private void AttachToContext<T>(T entity) where T : class, IEntity
{
var entry = _context.Entry(entity);
if (entry.State == EntityState.Detached)
{
var attachedEntity = FindExistingEntity<T>(entity.Id);
if (EntityExists(attachedEntity))
{
UpdateEntityValues(attachedEntity, entity);
}
else
{
entry.State = EntityState.Modified;
}
}
}
private T FindExistingEntity<T>(int id) where T : class
{
var set = _context.Set<T>();
return set.Find(id);
}
private void UpdateEntityValues<T>(T existing, T updated) where T : class
{
var attachedEntry = _context.Entry(existing);
attachedEntry.CurrentValues.SetValues(updated);
}
The usage would be AttachToContext(orderItem);.
Passing The Keys
private void AttachToContext<T>(T entity, params object[] id) where T : class
{
var entry = _context.Entry(entity);
if (entry.State == EntityState.Detached)
{
var attachedEntity = FindExistingEntity<T>(id);
if (EntityExists(attachedEntity))
{
UpdateEntityValues(attachedEntity, entity);
}
else
{
entry.State = EntityState.Modified;
}
}
}
private T FindExistingEntity<T>(object[] id) where T : class
{
var set = _context.Set<T>();
return set.Find(id);
}
private void UpdateEntityValues<T>(T existing, T updated) where T : class
{
var attachedEntry = _context.Entry(existing);
attachedEntry.CurrentValues.SetValues(updated);
}
The usage would be AttachToContext(orderItem, orderItem.Id);.
Another alternative would be using object set to get the primary key properties, then using reflection to get the value. To get the primary key properties has been explained in this post.

How to retrieve an object's Property name/value pairs on a custom object?

I have a custom object with varying datatypes for each property.
I would like to be able to do something like:
public void evalCI(configurationItem CI)
{
foreach (PropertyInformation n in CI)
{
Response.Write(n.Name.ToString() + ": " + n.Value.ToString() + "</br>");
}
}
My custom object is:
public class configurationItem : IEnumerable
{
private string serial;
private string model;
private DateTime? wstart;
private DateTime? wend;
private Int32 daysLeft;
private string platform;
private string productVersion;
private string manufacturer;
private bool verificationFlag;
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)GetEnumerator();
}
public string Serial
{
set { serial = value; }
get { return serial; }
}
public string Model
{
set { model = value; }
get { return model; }
}
public DateTime? Wstart
{
set { wstart = value; }
get { return wstart; }
}
public DateTime? Wend
{
set { wend = value; }
get { return wend; }
}
public Int32 DaysLeft
{
set { daysLeft = value; }
get { return daysLeft; }
}
public string Platform
{
set { platform = value; }
get { return platform; }
}
public string ProductVersion
{
set { productVersion = value; }
get { return productVersion; }
}
public string Manufacturer
{
set { manufacturer = value; }
get { return manufacturer; }
}
public bool VerificationFlag
{
set { verificationFlag = value; }
get { return verificationFlag; }
}
My expected output would be:
-Serial: 1234567
-Model: Mustang
-Wstart: 12/12/2005
-Wend: 12/11/2006
-DaysLeft: 0
-Platform: Car
-ProductVersion: GT
-Manufacturer: Ford
-VerificationFlag: true
At first I was getting an error that GetEnumerator() had to be implemented to use a foreach loop. The problem I keep running into is that all of the examples of Indexed Properties are of a single property with an indexable list, instead of an index for each property in the object. I was able to get intellisense to give me methods for PropertyInfo by adding:
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)GetEnumerator();
}
However, the 2nd GetEnumerator() throws:
Compiler Error Message: CS0103: The name 'GetEnumerator' does not exist in the current context.
What am I missing here? How do I modify my object to give me the results I expect from evalCI()?
You don't need to implement IEnumerable. What you do need to do is use Reflection.
This is from memory, but I believe it would look like this:
foreach (PropertyInfo n in typeof(configurationItem).GetProperties())
{
Response.Write(string.Format("{0}: {1}<br/>", n.Name, n.GetValue(CI, null)));
}
This - the code as written - will also only give you public properties, and non-indexed properties (but it doesn't look like you have any indexed properties).

ViewState Backed Property not Working for List<T>

I am trying to store a generic list in a viewstate-backed property as follows:
[Serializable]
public class UploadedFile
{
public string FileName { get; set; }
public Guid FileGuid { get; set; }
}
public List<UploadedFile> UploadedFiles
{
get
{
return (List<UploadedFile>) (ViewState["UploadedFiles"] ?? new List<UploadedFile>());
}
set
{
ViewState["UploadedFiles"] = value;
}
}
When I try to add an item to the list, the UploadedFiles.Count remains zero:
var uploadedFile = new UploadedFile {FileName = args.FileName, FileGuid = args.FileGuid};
UploadedFiles.Add(uploadedFile); // UploadedFiles.Count == 0 here!
Anyone have an idea here?
When you create the initial list, you dont save it into viewstate, try this..
public List<UploadedFile> UploadedFiles
{
get
{
var list = (List<UploadedFile>) (ViewState["UploadedFiles"] ??
new List<UploadedFile>());
ViewState["UploadedFiles"] = list;
return list;
}
set
{
ViewState["UploadedFiles"] = value;
}
}
What you're actually doing here is getting the property (which will initially return a new List) and then adding something to that new list, I think this is actually what you want to do:
List<UploadedFile> list = UploadedFiles;
list.Add(uploadedFile);
UploadedFiles = list;
This will write back to the ViewState after modifying the list.
To make life easier, I usually just do something like this to track ViewState for objects. Then you don't need any special handling when you refer to it elsewhere in code.
// Lazy loading object
protected List<string> ItemList {
get {
if (_ItemList==null) {
_ItemList = new List<string>();
}
return(_ItemList);
}
}
protected list<string> _ItemList=null;
// Save & Load it to viewstate as needed
protected override object SaveViewState()
{
if (_ItemList != null)
{
ViewState["ItemList"] = ItemList;
}
return base.SaveViewState();
}
protected override void LoadViewState(object savedState)
{
base.LoadViewState(savedState);
if (ViewState["ItemList"] != null)
{
_ItemList = (List<string>)ViewState["ItemList"];
}
}
private List Lista
set
{
ViewState.Add("Lista", value);
}
get
{
return ViewState["Lista"] != null ? (List<UploadedFile>)ViewState["Lista"] : null;
}
}

Resources