Adding and retrieving from a KeyedCollection - c#

I want to use a KeyedCollection to store a class against a string key value. I have the following code:
public class MyClass
{
public string Key;
public string Test;
}
public class MyCollection : KeyedCollection<string, MyClass>
{
public MyCollection() : base()
{
}
protected override String GetKeyForItem(MyClass cls)
{
return cls.Key;
}
}
class Program
{
static void Main(string[] args)
{
MyCollection col = new MyCollection();
col.Add(new MyClass()); // Here is want to specify the string Key Value
}
}
Can anyone tell me what I’m doing wrong here? Where do I specify the key value so that I can retrieve by it?

Your GetKeyForItem override is what specifies the key for an item. From the docs:
Unlike dictionaries, an element of KeyedCollection is not a key/value pair; instead, the entire element is the value and the key is embedded within the value. For example, an element of a collection derived from KeyedCollection<String,String> might be "John Doe Jr." where the value is "John Doe Jr." and the key is "Doe"; or a collection of employee records containing integer keys could be derived from KeyedCollection<int,Employee>. The abstractGetKeyForItem` method extracts the key from the element.
So in order for the item to be keyed correctly, you should set its Key property before adding it to the collection:
MyCollection col = new MyCollection();
MyClass myClass = new MyClass();
myClass.Key = "This is the key for this object";
col.Add(myClass);

The KeyedCollection is a base class for creating keyed collections, so there is quite a lot that you need to implement yourself.
Perhaps using a Dictionary would be easier and faster to work with.

I know it's slightly different, but have you considered implementing an indexer.
public string this[string index]
{
get {
// put get code here
}
set {
// put set code here.
}
}

Related

Use HashSet as Dictionary Key - Compare all elements

I am checking if a total group of edges already contains the connection between 2 points.
I want to use HashSet's that will contain 2 vectors as Dictionary keys. Then I want to be able to call a performant Dictionary.ContainsKey(hashSet). I want the contains/equality check to be dependent on the Vectors in the Set.
Fex. If I add HashSet [V000 V001] to the Dict. I want to get Dictionary.ContainsKey(HashSet [V001 V000]) return true. (HashSet, so the order can vary, just the same Elements)
The Problem seems to be, that the Dictionary.ContainsKey() method does see separately created HashSets as different objects, even though, they contain the same elements.
Dictionary<HashSet<Vector3>, Vector3> d = new Dictionary<HashSet<Vector3>, Vector3>();
HashSet<Vector3> s = new HashSet<Vector3>();
s.Add(Vector3.one);
s.Add(Vector3.zero);
d.Add(s);
HashSet<Vector3> s2 = new HashSet<Vector3>();
s2.Add(Vector3.zero);
s2.Add(Vector3.one);
bool doesContain = d.ContainsKey(s2); // should be true
You also may suggest a better way of doing this 'Contains()' check efficiently.
The HashSet type doesn't do the equality comparison you want out of the box. It only has reference equality.
To get what you want, you'll need a new type to use as the Dictionary key. The new type will have a HashSet property, and overload Equals() and GetHashCode(), and may as well implement IEquatable at this point as well.
I'll get you started:
public class HashKey<T> : IEquatable<HashKey<T>>
{
private HashSet<T> _items;
public HashSet<T> Items
{
get {return _items;}
private set {_items = value;}
}
public HashKey()
{
_items = new HashSet<T>();
}
public HashKey(HashSet<T> initialSet)
{
_items = initialSet ?? new HashSet();
}
public override int GetHashCode()
{
// I'm leaving this for you to do
}
public override bool Equals(Object obj)
{
if (! (obj is HashKey)) return false;
return this.GetHashCode().Equals(obj.GetHashCode());
}
public bool Equals(HashSet<T> obj)
{
if (obj is null) return false;
return this.GetHashCode().Equals(obj.GetHashCode());
}
}
You want to use a hashset as key.
So the keys are references where one key is one hashset reference.
The ContainsKey compare references.
For what you want to do, you can create a class that implements IEqualityComparer to pass it to the dictionary constructor.
https://learn.microsoft.com/dotnet/api/system.collections.generic.iequalitycomparer-1
If you want a full management, you should create a new class embedding the dictionary and implement your own public operations wrapping that of the dictionary : ContainsKey and all others methods you need.
public class MyDictionary : IEnumerable<>
{
private Dictionary<HashSet<Vector3>, Vector3> d
= new Dictionary<HashSet<Vector3>, Vector3>();
public int Count { get; }
public this...
public ContainsKey()
{
// implements your own comparison algorithm
}
public Add();
public Remove();
...
}
So you will have a strongly typed dictionary for your intended usage.

wrap dictionary for readability?

I'm building a translator that saves the translation in a dictionary where the first string is an identifier and the seconds string is the translated string.
It seems to me that the dictionary syntax is not very readable so I'm thinking about wrapping my dictionary like
class Translation : Dictionary<string,string>{}
and then also the keyvaluepair like
class SingleTranslation : KeyValuePair<string,string>
But the KeyValuePair class is sealed (can not be inherited). Does anyone have any suggestions on how I can make my dictionary more readable?
My biggest worry is when I have to iterate over the dictionary with
foreach(KeyValuePair<string,string> kvp in _translation)
{
string whatever = kvp.Value;
do stuff...
if(kvp.key)
do stuff..
}
I could of course create a string in the foreach that is called Identifier and set it equal to kvp.key. But I would prefer something like
foreach(SingleTranslation singleTranslation in _translation)
{
singleTranslation.Identifier ... do stuff...
}
Don't do that. Either use Dictionnary directly for complete access or use composition if you want more control.
Also use var in foreach loops. There is no value in defining a custom type for that (and it should not even works as you try to convert KeyValuePair to a derived class. And by the way, this is one reason why it is sealed.
If you really want to use custom types, and do not want to write much custom code, then maybe something like that could works for you:
class Translation
{
public Dictionary<string,string> Data { get } = new Dictionary<string,string>;
}
Then you could do:
Translation t; // Fill some data...
foreach (var item in t.Data) { … }
That way, you can ensure that you don't pass the improper dictionary to functions as you use distinct types for each case:
void DisplayTranslation(Translation t) { … }
If you want, you could improve your Translation class so that it does not expose the internal dictionary but expose appropriate members, properties and interfaces for the desired usage.
You could always use something other than a dictionary, like a class that inherits from List and then add an indexer on it so you could still use syntax like translations["myIndex"]. The code below could be optimized, but you can get the idea.
public class Translations : List<SingleTranslation>
{
public SingleTranslation this[string identifier]
{
get
{
return this.FirstOrDefault(p => p.Identifier == identifier);
}
set
{
SingleTranslation translation = this.FirstOrDefault(p => p.Identifier == identifier);
if (translation == null)
{
this.Add(value);
}
else
{
translation.Value = value.Value;
}
}
}
}
public class SingleTranslation
{
public SingleTranslation(string identifier, string value)
{
Identifier = identifier;
Value = value;
}
public string Identifier { get; set; }
public string Value { get; set; }
}
Sample usage:
public class Program
{
public static void Main()
{
Translations translations = new Translations();
translations.Add(new SingleTranslation("hello", "hola"));
translations.Add(new SingleTranslation("day", "día"));
foreach(SingleTranslation translation in translations)
{
Console.WriteLine("{0}: {1}", translation.Identifier, translation.Value);
}
translations["hello"].Value = "salut";
translations["day"].Value = "jour";
foreach(SingleTranslation translation in translations)
{
Console.WriteLine("{0}: {1}", translation.Identifier, translation.Value);
}
}
}
A working example of this is in this fiddle:
If readability is simply your issue, you could alias it within the namespace declaration.
using SingleTranslation = KeyValuePair<string,string>;

Accessor for formatted sub-list of dictionary possible without creating a new object every time?

first off - yes, I had a look at this question: Is object creation in getters bad practice?.
I am also not talking about initializing an object in the accessors / mutators, it is about a specific part of the object I want to be returned in a specific way.
My question is more specific; It does not necessarily only apply to C#, however I am currently looking for a solution to implement in my C# project.
I have a class with a dictionary that maps date objects to a decimal value. In one accessor, I want to return a list of all the keys of the dictionary, another accessors returns the values.
What I also want to have is an accessor that gives me the decimal values in a specific format. It would look something like this:
class Class
{
// Some other properties...
// ....
private Dictionary<DateTime, decimal> dict;
public Class(Dictionary<DateTime, decimal> dict)
{
this.dict = dict;
}
private string FormatTheWayIWant(decimal dt)
{
// Format decimal value.
string s = String.Format("{0:F}", dt);
return s;
}
public ReadOnlyCollection<DateTime> DateTimes
{
get { return new ReadOnlyCollection<DateTime>(this.dict.Keys.ToList()); }
}
public ReadOnlyCollection<decimal> Values
{
get { return new ReadOnlyCollection<decimal>(this.dict.Values.ToList()); }
}
public ReadOnlyCollection<string> FormattedStrings
{
get
{
// Format each decimal value they way I want.
List<string> list = new List<string>();
foreach (decimal dt in dict.Keys)
{
list.Add(FormatTheWayIWant(dt));
}
return new ReadOnlyCollection<string>(list);
}
}
}
This way I can make the following calls (which is my goal!):
DateTime dateTime = DateTimes[0];
decimal s = Values[0];
string formattedS = FormattedStrings[0];
The problem with this approach is that I create a new list everytime I invoke the FormattedStrings accessor, even if I only need one of the formatted strings. I know this is not good practice and can introduce unnecessary performance issues...
The alternatives I thought of are:
I could extend the decimal class and implement a custom ToString()-method.
Or overwrite the KeyValuePair<DateTime, decimal> class and use an indexer in my class.
Or I create a method with a parameter for the index and return just the one formatted string.
Or I could have an own list for the accessor, which gets updated in the set-method for my dictionary everytime I update the dictionary.
The question I have is, is there a way to make this work with an accessor instead of a method, creating custom classes or having strange side effects on other objects when assigning a value?
Thank you in advance.
Ofcourse this can be done with an accessor. You just have to create 3 separate classes for each desired element of your processed collection. Those classes should have their own indexers, so you would be able to access the elements as a list. The difference would be, that they compute each element on demand (wchich is called lazy initialization). So it would go like this (example for your FormattedStrings):
class Class
{
// ...
MyFormattedStrings FormattedStrings
{
get {return new MyFormattedStringsIndexer<string>(this.dict.Values.ToList());}
}
}
class MyFormattedStringsIndexer<T>
{
private IList<T> list; // we take only reference, so there is no overhead
public MyFormattedStringsCollection (IList<T> list)
{
this.list = list;
}
// the indexer:
public T this[int i]
{
get
{
// this is where the lazy stuff happens:
// compute the desired element end return it
}
set
{
// ...
}
}
}
Now you can use your Class like this:
string formattedS = FormattedStrings[5];
and each element you access will be computed as you access it. This solution also has the advantage of separating concerns, so should you ever had to implement different logic for one of your 3 accessors it would be just a matter of extending one of the indexers.
You can read more about indexeres here: http://msdn.microsoft.com/en-us/library/6x16t2tx.aspx
This is VB, but you get the idea...
Public Class Something
Public Property Items As Dictionary(Of DateTime, String)
Public Readonly Property FormattedItem(ByVal index As Int32) As String
' add error checking/handling as appropriate
Return Me.Items.Keys(index).ToString("custom format") ' or whatever your formatting function looks like.
End Property
End Class
It looks like a good candidate for a new class
public class MyObject
{
public DateTime Key {get;set;}
public String Name {get;set;}
public String FormattedString {get;}
}
And then it can be used in any container (List<MyObject>, Dictionary<MyObject>, etc).
Your Dates and Strings property getters are returning a new list on each call. Therefore if a caller does the following:
Class myClass = ...
for(i=0; i<myClass.Strings.Count; i++)
{
var s = myClass.Strings[i];
...
}
then each iteration of the loop will create a new list.
I'm not clear on what you're really trying to achieve here. You are wrapping the dictionary's Keys and Values properties in ReadOnlyCollections. This gives you an indexer, which doesn't have much meaning as the order of the Keys in a Dictionary<TKey, TValue> is unspecified.
Coming (at last!) to your question, if you want to do the formatting in a "lazy" manner, you could create a custom class that implements a readonly IList<string>, and wraps your list of keys (IList<DateTime>). Most of the implementation is boilerplate, and your indexer will do the formatting. You could also cache the formatted values so that you only format once if accessed multiple times. Something like:
public class MyFormattingCollection : IList<string>
{
private IList<decimal> _values;
private IList<string> _formattedValues;
public MyFormattingCollection(IList<DateTime> values)
{
_values = values;
_formattedValues = new string[_values.Count];
}
public string this[int index]
{
get
{
var result = _formattedValues[index];
if (result == null)
{
result = FormatTheWayIWant(_values[index]);
_formattedValues[index] = result;
}
return result;
}
set
{
// Throw: it's a readonly collection
}
}
// Boilerplate implementation of readonly IList<string> ...
}

How to access a custom collection property by its property name

I want to implement a custom collection that contains instances of my class.
This is my class, a bit simplified here.
public class Property : IComparable<Property>
{
public string Name;
public string Value;
public string Group;
public string Id;
...
...
public int CompareTo(Property other)
{
return Name.CompareTo(other.Name);
}
}
I am adding instances of Property to a List collection
Public List<Property> properties;
I can iterate through properties or access a specific property through the index position.
I want to however be able to access the property by its Name such that
var myColor = properties["Color"].Value;
and I do not have an efficient way to do this. I assume that properties should be written as a custom list collection class to achieve this. Does anyone have a code sample I can look at?
Thanks for the help.
Easiest methods were already mentioned, but I see two:
Method 1
Convert to dictionary and lookup there.
var props = properties.ToDictionary( x => x.Name );
Property prop = props["some name"];
Method 2
Create your own collection type which would support indexing
by your arbitrary type.
public class PropertyCollection : List<Property>
{
public Property this[string name]
{
get
{
foreach (Property prop in this)
{
if (prop.Name == name)
return prop;
}
return null;
}
}
}
and use this collection instead
PropertyCollection col = new PropertyCollection();
col.Add(new Property(...));
Property prop = col["some name"];
You can use a Dictionary:
Dictionary<string, Property> properties = new Dictionary<string, Property>();
//you add it like that:
properties[prop.Name] = prop;
//then access it like that:
var myColor = properties["Color"];
Use a Dictionary<string,Property> for this purpose. The key will be the property name and the value will be the Property instance itself.

C# How to make public getters and setters and private methods for a collection?

I'd like to have a class "A" with a (for example) SortedList collection "SrtdLst" property, and inside this class "A" allow the addition or subtraction of "SrtdLst" items. But in a instance of the class "A", only allow to get or set the content of the items, not to add new items or subtract the existing ones. In code:
class A
{
public SortedList<string, string> SrtdLst = new SortedList<string, string>();
public A()
{
// This must work:
SrtdLst.Add("KeyA", "ValueA");
// This too:
SrtdLst["KeyA"] = "ValueAAA";
}
}
class B
{
public A a = new A();
public B()
{
// I want the following code to fail:
a.SrtdLst.Add("KeyB", "ValueB");
// But this must work:
a.SrtdLst["KeyA"] = "ValueBBB";
}
}
UPDATE: I want to create a class like System.Data.SqlClient.SqlCommand. For the Stored Procedures you can use the member "DeriveParameters" that fills a collection of "Parameters", so only the value of each item can be modified.
How can this be done?
If you want to ban the modifying operations at compile time, you need a type-safe solution.
Declare an interface for the publicly allowed operations. Use that interface as the property type.
public interface IReadOnlyList<T>
{
T this[int index] { get; }
int Count { get; }
}
Then declare a class that implements that interface and inherits from the standard collection class.
public class SafeList<T> : List<T>, IReadOnlyList<T> { }
Assuming you get the interface definition right, you won't need to implement anything by hand, as the base class already provides the implementations.
Use that derived class as the type of the field that stores the property value.
public class A
{
private SafeList<string> _list = new SafeList<string>();
public IReadOnlyList<string>
{
get { return _list; }
}
}
Within class A, you can use _list directly, and so modify the contents. Clients of class A will only be able to use the subset of operations available via IReadOnlyList<T>.
For your example, you're using SortedList instead of List, so the interface probably needs to be
public interface IReadOnlyDictionary<K, V> : IEnumerable<KeyValuePair<K, V>>
{
V this[K index] { get; }
}
I've made it inherit IEnumerable as well, which is readonly anyway, so is perfectly safe. The safe class would then be:
public class SafeSortedList<K, V> : SortedList<K, V>, IReadOnlyDictionary<K, V> { }
But otherwise it's the same idea.
Update: just noticed that (for some reason I can't fathom) you don't want to ban modifying operations - you just want to ban SOME modifying operations. Very strange, but it's still the same solution. Whatever operations you want to allow, "open them up" in the interface:
public interface IReadOnlyDictionary<K, V> : IEnumerable<KeyValuePair<K, V>>
{
V this[K index] { get; set; }
}
Of course, that's the wrong name for the interface now... why on earth would you want to ban adding via Add but not ban it via the indexer? (The indexer can be used to add items, just as the Add method can.)
Update
From your comment I think you mean that you want to allow assignment to the value of an existing key/value pair, but disallow assignment to a previously unknown key. Obviously as keys are specified at runtime by strings, there's no way to catch that at compile time. So you may as well go for runtime checking:
public class FixedSizeDictionaryWrapper<TKey, TValue> : IDictionary<TKey, TValue>
{
IDictionary<TKey, TValue> _realDictionary;
public FixedSizeDictionaryWrapper(IDictionary<TKey, TValue> realDictionary)
{
_realDictionary = realDictionary;
}
public TValue this[TKey key]
{
get { return _realDictionary[key]; }
set
{
if (!_realDictionary.Contains(key))
throw new InvalidOperationException();
_realDictionary[key] = value;
}
}
// Implement Add so it always throws InvalidOperationException
// implement all other dictionary methods to forward onto _realDictionary
}
Any time you have an ordinary dictionary and you want to hand it to some method that you don't trust to update the existing values, wrap it in one of these.
EDIT: Original answer is below. As earwicker points out, I hadn't noticed that you aren't asking for it to be readonly - just to prevent the Add operation. That doesn't sound like a good idea to me, as the only difference between Add and the indexer-setter is that Add throws an exception if the element is already present. That could easily be faked up by the caller anyway.
Why do you want to restrict just that one operation?
Original answer
For one thing, don't use public fields. That's a surefire way to run into problems.
It looks like you want a read-only wrapper class round an arbitrary IDictionary. You can then have a public property which returns the wrapper, while you access the private variable from within your class. For example:
class A
{
private SortedList<string, string> sortedList = new SortedList<string, string>();
public IDictionary<string, string> SortedList
{
get { return new ReadOnlyDictionaryWrapper(sortedList);
}
public A()
{
sortedList.Add("KeyA", "ValueA");
sortedList["KeyA"] = "ValueAAA";
}
}
Now you've just got to find a ReadOnlyDictionary implementation... I can't implement it right now, but I'll be back later if necessary...
Just make the list private, and expose it as an indexer:
class A {
private SortedList<string, string> _list;
public A() {
_list = new SortedList<string, string>()
}
public string this[string key] {
get {
return _list[key];
}
set {
_list[key] = value;
}
}
}
Now you can only access the items using the index:
a["KeyA"] = "ValueBBB";
However, as the indexer of the list allows creation of new items, you would have to add code in the indexer to prevent that if you don't want that do be possible.
If the keys are known outside of the class then you can add a ChangeItem(key, newValue) and ReadItem(key) to your wrapper class. Then keep the SortedList private to the class.

Categories

Resources