Can you do
array['Name'];
In C#
Rather than:
array[0];
I know you can do that in PHP but is there an equivelent for C#, although im thinking highley unlikely :(
it's called a Dictionary in C#. Using generics you can actually index by any type. Like so:
Dictionary<Person, string> dictionary = new Dictionary<Person, string>();
Person myPerson = new Person();
dictionary[myPerson] = "Some String";
...
string someString = dictionary[myPerson];
Console.WriteLine(someString);
This obviously prints, "Some String" to the console.
This is an example of the flexibility of the dictionary. You can do it with a string as an index too, like you asked for.
Arrays don't work like that in C#, but you can add an indexer property to any class:
class MyClass
{
public string this[string key]
{
get { return GetValue(key); }
set { SetValue(key, value); }
}
}
Then you can write the type of statements you ask against this:
MyClass c = new MyClass();
c["Name"] = "Bob";
This is how string-based indexed access to Dictionary<TKey, TValue>, NameValueCollection and similar classes are implemented. You can implement multiple indexers as well, for example, one for the index and one for the name, you just add another property as above with a different parameter type.
Several built-in framework classes already have these indexers, including:
SortedList<TKey, TValue>
Dictionary<TKey, TValue>
SortedDictionary<TKey, TValue>
NameValueCollection
Lookup<TKey, TValue> (in System.Linq)
...and more. These are all designed for slightly different purposes, so you'll want to read up on each and see which one's appropriate for your requirement.
Dictionary<string, whatyouwanttostorehere> myDic =
new Dictionary<string, whatyouwanttostorehere>();
myDic.Add("Name", instanceOfWhatIWantToStore);
myDic["Name"];
Related
Recently, I have found out that indexer can accept an array of arguments as params:
public class SuperDictionary<TKey, TValue>
{
public Dictionary<TKey, TValue> Dict { get; } = new Dictionary<TKey, TValue>();
public IEnumerable<TValue> this[params TKey[] keys]
{
get { return keys.Select(key => Dict[key]); }
}
}
Then, you will be able to do:
var sd = new SuperDictionary<string, object>();
/* Add values */
var res = sd["a", "b"];
However, I never met such usage in .NET Framework or any third-party libraries. Why has it been implemented? What is the practical usage of being able to introduce params indexer?
The answer has been found in a minute after posting the question and looking through the code and documentation - C# allows you to use any type as a parameter for indexer, but not params as a special case.
According to MSDN,
Indexers do not have to be indexed by an integer value; it is up to you how to define the specific look-up mechanism.
In other words, indexer can be of any type. It can either be an array...
public IEnumerable<TValue> this[TKey[] keys]
{
get { return keys.Select(key => Dict[key]); }
}
var res = sd[new [] {"a", "b"}];
or any kind of another unusual type or collection, including params array, if it seems to be convenient and suitable in your case.
In this thread
How to get null instead of the KeyNotFoundException accessing Dictionary value by key?
in my own answer I used explicit interface implementation to change the basic dictionary indexer behaviour not to throw KeyNotFoundException if the key was not present in the dictionary (since it was convinient for me to obtain null in such a case right inline).
Here it is:
public interface INullValueDictionary<T, U>
where U : class
{
U this[T key] { get; }
}
public class NullValueDictionary<T, U> : Dictionary<T, U>, INullValueDictionary<T, U>
where U : class
{
U INullValueDictionary<T, U>.this[T key]
{
get
{
if (ContainsKey(key))
return this[key];
else
return null;
}
}
}
Since in a real application I had a list of dictionaries, I needed a way to access the dictionaries from the collection as an interface. I used simple int indexer to acess each element of the list.
var list = new List<NullValueDictionary<string, string>>();
int index = 0;
//...
list[index]["somekey"] = "somevalue";
The easiest thing was to do something like this:
var idict = (INullValueDictionary<string, string>)list[index];
string value = idict["somekey"];
The question raised when I decided to try to use covariance feature to have a collection of interfaces to use instead. So I needed an interface with covariant type parameter for the cast to work. The 1st thing that came to my mind was IEnumerable<T>, so the code would look like this:
IEnumerable<INullValueDictionary<string, string>> ilist = list;
string value = ilist.ElementAt(index)["somekey"];
Not that nice at all, besides ElementAt instead of an indexer is way worse.
The indexer for List<T> is defined in IList<T>, and T there is not covariant.
What was I to do? I decided to write my own:
public interface IIndexedEnumerable<out T>
{
T this[int index] { get; }
}
public class ExtendedList<T> : List<T>, IIndexedEnumerable<T>
{
}
Well, few lines of code (I don't even need to write anything in ExtendedList<T>), and it works as I wanted:
var elist = new ExtendedList<NullValueDictionary<string, string>>();
IIndexedEnumerable<INullValueDictionary<string, string>> ielist = elist;
int index = 0;
//...
elist[index]["somekey"] = "somevalue";
string value = ielist[index]["somekey"];
Finally the question: can this covariant cast be somehow achieved without creating an extra collection?
You can try use IReadOnlyList<T>, which is implemented by List<T>.
Note that I've added one instance of NullValueDictionary<string, string> to List, so that you won't get ArgumentOutOfRangeException at elist[index] line.
IReadOnlyList<NullValueDictionary<string, string>> elist = new List<NullValueDictionary<string, string>>
{
new NullValueDictionary<string, string>()
};
IReadOnlyList<INullValueDictionary<string, string>> ielist = elist;
int index = 0;
//...
elist[index]["somekey"] = "somevalue";
string value = elist[index]["somekey"];
Edit: I've searched for covariant interfaces and collections with indexes prior to .NET 4.5, but found none. Still I think there are a little bit easier solution, than to create separate interface - just to cast one collection to another.
List<INullValueDictionary<string, string>> ielist = elist.Cast<INullValueDictionary<string, string>>().ToList();
Or use covariance gained from arrays
INullValueDictionary<string, string>[] ielist = elist.ToArray()
LINQ has some optimization that work on whole type compatibility, so you won't iterate over sequence if those types are compatible.
Cast implementation taken from MONO Linq
public static IEnumerable<TResult> Cast<TResult> (this IEnumerable source)
{
var actual = source as IEnumerable<TResult>;
if (actual != null)
return actual;
return CreateCastIterator<TResult> (source);
}
Note that I have changed INullValueDictionary<T, U> interface to contain set in the property so that ielist[index]["somekey"] = "somevalue"; will work.
public interface INullValueDictionary<T, U> where U : class
{
U this[T key] { get; set; }
}
But again - if creating a new Interface and class is ok for you and you don't want to mess around with casts everywhere - I think it is a good solution, if you have considered at the constraints, it gives.
In search of covariance in mscorlib
This probably won't be interesting to you, but I've just wanted to find out what Types are covariant in mscorlib assembly. By running next script I received only 17 types are covariant, 9 of which are Funcs. I have omitted IsCovariant implementation, because this answer is too long even without it
typeof(int).Assembly.GetTypes()
.Where(type => type.IsGenericType)
.Where(type=>type.GetGenericArguments().Any(IsCovariant))
.Select(type => type.Name)
.Dump();
//Converter`2
//IEnumerator`1
//IEnumerable`1
//IReadOnlyCollection`1
//IReadOnlyList`1
//IObservable`1
//Indexer_Get_Delegate`1
//GetEnumerator_Delegate`1
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Bidirectional 1 to 1 Dictionary in C#
Im curious if a datastructure exists in the standard .net libraries that can represent a 1-1 relationship, such as the following
1-a
4-b
6-c
5-d
Where I can say:
thisstructure[1] // returns "a"
thisstructure.GetKey["d"] // return 5
I understand all keys would have to be unique, does anything similar exist?
Thanks!
Yes- it's called KeyedCollection. It is intended to be subclassed and provides indexed access as well as access by a property derived from the added item. I usually make a generic subclass:
public class GenericKeyedCollection<TKey, TValue> : KeyedCollection<TKey, TValue> {
private readonly Func<TValue, TKey> _keyGenerator;
public GenericKeyedCollection(Func<TValue, TKey> keyGenerator) {
_keyGenerator = keyGenerator;
}
protected override int GetKeyForItem(TValue item)
{
return _keyGenerator(item);
}
}
To use it:
var myCollection = new GenericKeyedCollection<String, Car>(c=>c.Model);
myCollection.Add(new Car("Ford", "Mustang"));
var byIndex = myCollection[0];
var byModel = myCollection["Mustang"];
The only caveat is that the derived property (the "key") mustn't change after the item has been added.
If your key is not a property of the value, then you can use a Tuple<T1, T2> to combine the key and value:
var myCollection = new GenericKeyedCollection<String, Tuple<String, Car>>(t=>t.Item1);
myCollection.Add(new Tuple<String, Car>("Foo", Car("Ford", "Mustang")));
var byIndexCar = myCollection[0].Item2;
var byItem1Car = myCollection["Foo"].Item2;
Could this method fit your needs?
public static class Extensions
{
public static TKey GetKey<TKey, TValue>(this Dictionary<TKey, TValue> dict, TValue value)
{
int index = dict.Values.ToList().IndexOf(value);
if (index == -1)
{
return default(TKey); //or maybe throw an exception
}
return dict.Keys.ToList()[index];
}
}
You could then use it like so:
Dictionary<int, char> dict = new Dictionary<int, char>();
dict.Add(1, 'a');
dict.Add(4, 'b');
dict.Add(6, 'c');
dict.Add(5, 'd');
Console.WriteLine(dict.GetKey('d')); //5
The Dictionary....or IDictionary interface is the closest I can think of to what you want. It doesn't have quite so simple a searching operation, in that searching on a value can return the key, but I do know you can search on a key to get a value. providing functionality for the reverse in a custom extended class wouldn't be difficult at all.
MSDN IDictionary page
Say I have a Dictionary object which contains many instances of an object called SomeObject and each SomeObject has properties named Property1 and Property2. Now say I have a method which can return a new Dictionary sorted by Property1. However, I'd like to generalize that method such that I can tell it which property to sort by.
For example, to do this, I know I could easily have two separate methods such as:
public Dictionary<string, SomeObject> SortByProp1(Dictionary<string, SomeObject> dict) { ... }
public Dictionary<string, SomeObject> SortByProp2(Dictionary<string, SomeObject> dict) { ... }
But, I'm wondering if it's possible to combine these into one method in which I can give a parameter to identify which method to return? I don't know of a way to generalize a property like that...
Note: I do realize I could always use something like an if-statement which could be based on a string of the property name, but that doesn't seem like a very elegant, acceptable answer much better than just having two separate methods to begin with.
The method you seek is built into the IEnumerable<T> interface, and is OrderBy, though it might not work out as smothly for a Dictionary as you might like.
Dictionary<TKey, TValue> implements IEnumerable<KeyValuePair<TKey, TValue>>, so its OrderBy method takes a lambda expression which itself takes a KeyValuePair<TKey, TValue>, and returns a selector method that describes what you're sorting by.
For example, if you have Dictionary<int, Customer>, this will return to you an IEnumerable<KeyValuePair<int, Customer>> sorted by customer name:
myDict.OrderBy(kvp => kvp.Value.Name);
Then to get just the customers themselves in this sorted order, you'd say:
IEnumerable<Customer> orderedByName = myDict.OrderBy(kvp => kvp.Value.Name).Select(kvp => kvp.Value);
Can you try adding a generic type parameter, for the ordering key - and accept a predicate for the ordering?
Such as:
public Dictionary<string, SomeObject> SortByProp<TProp>(Dictionary<string, SomeObject> dict, Expression<SomeObject,TProp> orderPredicate)
{
return dict.OrderBy(orderPredicate);
}
// Usage:
SortByProp(apples, x => x.AppleColor);
SortByProp(oranges, x => x.OrangeType);
You can accept a delegate to select the property:
public Dictionary<string, SomeObject> Sort<TProperty>(Dictionary<string, SomeObject> dict, Func<SomeObject, TProperty> selector) { ... }
You can call it like this:
var sortedDict = Sort(dict, o => o.Property1);
Basically, I want something like this:
Dictionary<object, string> dict = new Dictionary<object, string>();
dict.Add(null, "Nothing");
dict.Add(1, "One");
Are there any built into the base class library that allow this? The preceding code will throw an exception at runtime when adding the null key.
You could avoid using null and create a special singleton value class that does the same thing. For example:
public sealed class Nothing
{
public static readonly Nothing Value = new Nothing();
private Nothing() {}
}
Dictionary<object, string> dict = new Dictionary<object, string>();
dict.add(Nothing.Value, "Nothing");
dict.add(1, "One");
This approach will fail to work if you intend to make your collection more strongly typed - let's say for example you want the key to be a string. Since string is sealed you can't inherit from it to create a "special value" substitute for null. Your alternatives become a bit more complicated. You could:
Create some special constant value to represent the "empty" / "null" case. Kind of hacky and definitely a path to confusion. This can be a viable approach if the dictionary is completely private to some implementation class and you can write some Encode/Decode utility methods to avoid spreading the knowledge of how you translate keys all over the place.
Create your own implementation of IDictionary that internally delegates to a Dictionary<> instance - except for the case of null. This violates the documented expectations for the IDictionary<> interface which does say that null keys should throw an exception. But you may be able to get away with it if it's the only way to solve your real problem. This only works if you own and create the dictionary instance.
Find a way to solve your problem without storing a "null" key in the dictionary. For example, consider not populating the null key in the dictionary and having some special case logic to deal with it. Keys have to be hashable and comparable to work with the underlying implementation, which is why null is prohibited normally.
As an aside, does your dictionary key really need the key to be object? This can lead to subtle bugs due to reference equality being used where you may have intended Equals() to be evaluated as the basis for comparison.
How about this?
public class NullableDictionnary<T1, T2> : Dictionary<T1, T2>
{
T2 null_value;
public T2 this[T1 key]
{
get
{
if (key == null)
{ return null_value; }
return base[key];
}
set
{
if (key == null)
{ null_value = value; }
else
{ base[key] = value; }
}
}
}
NameValueCollection can take a null key but it does not implement IDictionary. It would however be pretty easy to derive from DictionaryBase and provide Add/Remove/Indexers etc that simply replace null with something built in like:
class MyDictionary : DictionaryBase {
private readonly object nullKey = new object();
void Add(object key, string value) {
if ( key == null ) { key = nullKey; }
.. call base methods
}
}
You can simply use ValueTuple as a wrapper for key, for example:
Dictionary<ValueTuple<string?>, string>
No need for a different implementation of Dictionary.
Take a look at my answer here:
https://stackoverflow.com/a/22261282/212272
You will also be able to keep your dictionary strongly typed:
var dict = new Dictionary<NullObject<int?>, string>();
dict[1] = "one int";
dict[null] = "null int";
Assert.AreEqual("one int", dict[1]);
Assert.AreEqual("null int", dict[null]);
If key is enum, you can use not existing value instead of null like (YourEnum)(-1)
Does the key literally need to be NULL? The key in the collection works out to be an index. It doesn't make a lot of sense to me to have NULL for an index in a collection.
Maybe create a new class
public class ObjectEntry
{
public object objRef;
public string desc;
public ObjectEntry(object objectReference)
{
objRef = objectReference;
if (objRef = null) {desc = "Nothing";}
else {desc = objRef.Description;} //or whatever info you can get from a proper objRef value
}
}
newObj = new ObjectEntry(null);
dict.add(newObj, newObj.desc);
A slight variation on jestro's answer to make for a cleaner(to me) solution that makes it more explicit what you are trying to do. Obviously this could be extended as needed. But you get the picture, just make a wrapper.
public class NullDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
private TValue _default;
public new TValue this[TKey key]
{
get {
if(key == null)
{
return _default;
}
return _decorated[key];
}
}
private Dictionary<TKey, TValue> _decorated;
public NullDictionary( Dictionary<TKey,TValue> decorate, TValue defaultValue = default)
{
_decorated = decorate;
_default = defaultValue;
}
}